Property declared in my class isn't recognized when attempting to use it inside a function? - swift

I've checked for the misspelling of the property, that's definitely not the case. I'm trying to use the property mySong that I declared in my class inside the parseSongs() function.
That function isn't inside the class but it's in the same file. And the target membership of that class is set to the project name as are the other files as well.
I'm very confused why the compiler isn't recognizing the name of my property in the parseSongs()?
I can declare the property outside of the class but I should be able to use it even if it's declared inside the class.
import UIKit
class SongsTableViewController: UITableViewController {
//A property that is an array of type 'Song'
var mySong = [Song]()
private let cache = NSCache()
private func fetchMyData(){
let myUrl = NSURL(string: "http://itunes.apple.com/search?term=beatles&country=us")!
let mySession = NSURLSession.sharedSession()
//The work to be queued initiates
let myTask = mySession.dataTaskWithURL(myUrl){
//This closure right here is the Completion Handler
data, response, error in
if error != nil{
//Handle error
}else{
let myHttpResponse = response as! NSHTTPURLResponse
switch myHttpResponse.statusCode {
case 200..<300:
print("OK")
print("data: \(data)")
default: print("request failed: \(myHttpResponse.statusCode)")
}
}
}
myTask.resume()
}
}
func parseJson(myData data: NSData){
do{
let json: AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: [])
if let unwrappedJson: AnyObject = json{
parseSongs(unwrappedJson)
}
}catch{
}
}
func parseSongs(json1: AnyObject){
mySong = []
//Optional Binding
if let array = json1["results"] as? [[String:AnyObject]]{
//For-In loop
for songDictionary in array{
if let title = songDictionary["trackName"] as? NSString{
if let artist = songDictionary["artistName"] as? NSString{
if let albumName = songDictionary ["collectionName"] as? NSString{
if let artWorkUrl = songDictionary["artWorkUrl100"] as? NSString {
let song = Song(artist: (artist as String), title: (title as String), albumName: (albumName as String), artWorkUrl: (artWorkUrl as String))
mySong.append(song)
}
}
}
}
}
dispatch_async(dispatch_get_main_queue()){
self.tableView.reloadData()
}
}
}

To use the property outside which declared inside a class you have to follow this
SongsTableViewController().theProperty
If you declare it outside class then you can access it in function of outside class

Related

How convert Realm data to Json on Swift? Realm version 10.11.0

until version 10.7.6 of Realm I could convert to dictionary and then to json with this code below, but the ListBase class no longer exists.
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dictionary = self.dictionaryWithValues(forKeys: properties)
let mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeys(dictionary)
for prop in self.objectSchema.properties as [Property] {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase { /*Cannot find type 'ListBase' in scope*/
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
let object = nestedListObject._rlmArray[index] as! Object
objects.append(object.toDictionary())
}
mutabledic.setObject(objects, forKey: prop.name as NSCopying)
}
}
return mutabledic
}
}
let parameterDictionary = myRealmData.toDictionary()
guard let postData = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: []) else {
return
}
List now inherits from RLMSwiftCollectionBase apparently, so you can check for that instead. Also, this is Swift. Use [String: Any] instead of NSDictionary.
extension Object {
func toDictionary() -> [String: Any] {
let properties = self.objectSchema.properties.map { $0.name }
var mutabledic = self.dictionaryWithValues(forKeys: properties)
for prop in self.objectSchema.properties as [Property] {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic[prop.name] = nestedObject.toDictionary()
} else if let nestedListObject = self[prop.name] as? RLMSwiftCollectionBase {
var objects = [[String: Any]]()
for index in 0..<nestedListObject._rlmCollection.count {
let object = nestedListObject._rlmCollection[index] as! Object
objects.append(object.toDictionary())
}
mutabledic[prop.name] = objects
}
}
return mutabledic
}
}
Thanks to #Eduardo Dos Santos. Just do the following steps. You will be good to go.
Change ListBase to RLMSwiftCollectionBase
Change _rlmArray to _rlmCollection
Import Realm

Assign value to Class Member within Function

I have a class that has two member variables and a function. The function is called when the user navigates to a new storyboard and uses a http GET request with member variable y to assign a value to member variable x. After the function is finished, I try to assign x to the new storyboard's variable, however it is nil. How do I assign a value to x within the function and then pass x to the new storyboard?
import UIKit
import os.log
class testViewController: UIViewController {
var x: XClass!
var y = “1234”
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
switch(segue.identifier ?? "") {
case “ZViewController”:
guard let zviewcontroller = segue.destination as? ZViewController else{
fatalError("Unexpected Destination: \(segue.destination)")
}
loadXDetail()
zviewcontroller.x = x
default:
os_log("Not ZViewController Segue", log: OSLog.default, type: .debug)
}
}
private func loadX(){
// credentials encoded in base64
let username = “***”
let password = “***”
let loginData = String(format: "%#:%#", username, password).data(using: String.Encoding.utf8)!
let base64LoginData = loginData.base64EncodedString()
// create the request
let url = URL(string: "https://example.com")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("Basic \(base64LoginData)", forHTTPHeaderField: "Authorization")
//making the request
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse {
// check status code returned by the http server
print("status code = \(httpStatus.statusCode)")
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
let items = json["items"] as? [[String: Any]] ?? []
for dic in items{
//guard let api = dic["Type"] as? String else {return}
let a = dic[“A”] as! String
let b = dic[“B”] as! String
let c = dic[“C”] as! String
self.x = XClass(y: y, a: a, b: b, c: c)!
}
} catch let error as NSError {
print(error)
return
}
}
}
task.resume()
}
}
You can't prevent a segue inside prepare(for segue until your request finishes , you need to start the call to the asynchonous method when you need to navigate
loadX()
then inside the completion of let task = URLSession.shared.dataTask(with: request) do
self.x = XClass(y: y, a: a, b: b, c: c)!
}
DispatchQueue.main.async {
self.performSegue(withIdentifier:"SegueID",sender:nil)
}
and at that moment the x var has a correct value according to the response
another thing you may need x as any array as it will contain the last value from this loop
for dic in items{
//guard let api = dic["Type"] as? String else {return}
let a = dic[“A”] as! String
let b = dic[“B”] as! String
let c = dic[“C”] as! String
self.x = XClass(y: y, a: a, b: b, c: c)!
}
plus consider using Codable to decode your response instead of JSONSerialization
swift 4.2 / Xcode 10.1:
There are few ways to pass data between viewControllers or classes.
The easiest one is using Global variable. For Example:
import UIKit
var myGlobalVariable = "" //Or any Type you need
class testViewController: UIViewController {
private func loadX(){
//Do some stuff ...
myGlobalVariable = x
}
import UIKit
class ZViewController: UIViewController {
override func viewDidLoad() {
print(myGlobalVariable)
}
Or, using singleton pattern. For Example:
Create a class like:
import Foundation
class SetVariable {
var test: String? //Or any type you need
private init () {}
static let shared = SetVariable.init()
}
class testViewController: UIViewController {
private func loadX(){
//Do some stuff ...
SetVariable.shared.test = x
}
class ZViewController: UIViewController {
override func viewDidLoad() {
print(SetVariable.shared.test)
}

swift 4 extensions Cannot pass immutable value as inout argument: 'self' is immutable" error message

I created as simple extension to UIViewController, but when I call the method inside, even applying inout keyword I got "Cannot pass immutable value as inout argument: 'self' is immutable" error message. How could resolve it?
in my VC I have this var
var asyncComicEntityArray : [NSManagedObject]! = []
in my button I implemented extension this way
searchIfOwnedInExtension(asynchArrayToUse: &asyncComicEntityArray, showWhereOwnedIs: true)
and here is the extension in a separate swift file
EXTENSION
import Foundation
import UIKit
import CoreData
extension UIViewController {
//needs a var asyncComicEntityArray : [NSManagedObject]! = []
func searchIfOwnedInExtension(asynchArrayToUse: inout [NSManagedObject], showWhereOwnedIs: Bool) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {return}
let managedContext = appDelegate.persistentContainer.viewContext
let comicFetch : NSFetchRequest<Comic> = Comic.fetchRequest()
let predicateForRequest = NSPredicate(format: "inCollection == %#", NSNumber(booleanLiteral: showWhereOwnedIs))
comicFetch.predicate = predicateForRequest
do {
asynchArrayToUse = try managedContext.fetch(comicFetch)
} catch let error as NSError {
print("Fetch error: \(error) description: \(error.userInfo)")
}
guard asynchArrayToUse != nil else {return}
for comic in asynchArrayToUse {
var comicTouse = Comic()
comicTouse = comic as! Comic
print("comic title: \(comicTouse.comicTitle!), is it in collection? : \(comicTouse.inCollection)")
}
}
}

Cannot convert value of type 'String?!' to expected argument type 'Notifications'

I am trying to check the id of a record before I put it into the array, using xcode swift
here is the code. But, i get the following error
Notifications.swift:50:46: Cannot convert value of type 'String?!' to expected argument type 'Notifications'
on this line
*if (readRecordCoreData(result["MessageID"])==false)*
Please can some one help to explain this error
import CoreData
struct Notifications{
var NotifyID = [NSManagedObject]()
let MessageDesc: String
let Messageid: String
init(MessageDesc: String, Messageid:String) {
self.MessageDesc = MessageDesc
self.Messageid = Messageid
// self.MessageDate = MessageDate
}
static func MessagesWithJSON(results: NSArray) -> [Notifications] {
// Create an empty array of Albums to append to from this list
var Notification = [Notifications]()
// Store the results in our table data array
if results.count>0 {
for result in results {
//get fields from json
let Messageid = result["MessageID"] as! String
let MessageDesc = result["MessageDesc"] as? String
let newMessages = Notifications(MessageDesc: MessageDesc!, Messageid:Messageid)
//check with id's from core data
if (readRecordCoreData(result["MessageID"])==false)
{
Notification.append(newMessages)
}
}
}
return Notification
}
//check id
func readRecordCoreData(Jsonid: String) -> Bool {
var idStaus = false
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
//2
let fetchRequest = NSFetchRequest(entityName: "ItemLog")
//3
do {
let resultsCD = try! managedContext.executeFetchRequest(fetchRequest)
if (resultsCD.count > 0) {
for i in 0 ..< resultsCD.count {
let match = resultsCD[i] as! NSManagedObject
let id = match.valueForKey("notificationID") as! String
if (Jsonid as String! == id)
{
idStaus = true
}
else{
idStaus = false
}
}
}
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
return idStaus
}
One of your methods is static and the other one is not :
func readRecordCoreData(Jsonid: String) -> Bool
static func MessagesWithJSON(results: NSArray) -> [Notifications]
Depending on what you want to accomplish you could declare both static, none, or replace
//check with id's from core data
if (readRecordCoreData(result["MessageID"])==false)
{
Notification.append(newMessages)
}
By
//check with id's from core data
if (Notifications.readRecordCoreData(Messageid)==false)
{
Notification.append(newMessages)
}
Not sure if the code will work past compilation however as there are many readability issues

Cannot assign value to stored property from within computed property

I created a struct in which I have a property '_photo' that is lazily assigned when the computed property 'photo' is called. I keep getting the error
Cannot assign to '_photo' in 'self'
Here is the code. I wrote the computed method in both Swift 1.1 (photo1) and swift 1.2 (photo2) syntax. Both give the same compile time error as noted above.
What changes are needed to fix that error?
import UIKit
public struct PhotoStruct {
var _photo:UIImage?
var urlString:String?
init(image:UIImage?, url:String?){
self._photo = image
self.urlString = url
}
init(url:String?){
self.urlString = url
}
var photo1:UIImage? {
if let theURL = self._photo {
return self._photo
}else{
if let urlString = self.urlString{
if let url = NSURL(string: urlString as String){
if let imageData :NSData = NSData(contentsOfURL: url){
if let image:UIImage = UIImage(data:imageData){
self._photo = image //** Cannot assign error is here**
}
}
}
}
return self._photo
}
}
var photo2:UIImage? {
if let theURL = self._photo {
return self._photo
}else{
if let urlString = self.urlString,
url = NSURL(string: urlString as String),
imageData :NSData = NSData(contentsOfURL: url),
image:UIImage = UIImage(data:imageData){
self._photo = image //** Cannot assign error is here**
}
return self._photo
}
}
}
As for struct, If you want to mutate the self property inside computed properties, you have to explicitly declare the getter as mutating get { .. }
public struct PhotoStruct {
var _photo:UIImage?
var urlString:String?
init(image:UIImage?, url:String?){
self._photo = image
self.urlString = url
}
init(url:String?){
self.urlString = url
}
var photo1:UIImage? {
mutating get {
// ^^^^^^^^^^^^
// you can set `self._photo = image` here
}
}
var photo2:UIImage? {
mutating get {
// ^^^^^^^^^^^^
// you can set `self._photo = image` here
}
}
}
Of course, the struct itself have to be mutable:
var pVar:PhotoStruct = PhotoStruct(image: nil, url: nil)
pVar.photo1 // no problem
let pLet:PhotoStruct = PhotoStruct(image: nil, url: nil)
pLet.photo1 // < [!] error: immutable value of type 'PhotoStruct' only has mutating members named 'photo1'
One caveat:
As far as I know, mutating get { } feature is undocumented on the language reference.
Structs are value types and they are immutable.
This means that you cannot set variable and mutate self.
If you need to mutate struct, you have to make mutating func
public struct PhotoStruct {
var _photo:UIImage?
var urlString:String?
mutating func loadPhoto() -> UIImage {
.. Code here
_photo = UIImage(data:imageData)
// Here you mutate a struct, but it's ok because we make method as mutating
}
}
In you example I would make a mutating method instead of property
mutating func photo () -> UIImage? {
if let photo = self._photo {
return photo
} else {
if let urlString = self.urlString,
url = NSURL(string: urlString),
imageData = NSData(contentsOfURL: url),
image = UIImage(data:imageData) {
self._photo = image
}
return self._photo
}
}
PhotoStruct is a struct and therefore a value type. For value types,
only methods explicitly marked as mutating can modify the properties
of self, so this is not possible within a computed property.
If you change PhotoStruct to be a class then your code compiles
without problems.