So I have this class in City.swift:
class City {
class Entry {
let name : String
init(name : String) {
self.name = name
}
}
let cities = []
}
And in another file I want to add to an array like this:
var city = City()
city.cities = City(name: "Test")
And I want to be able to call it by indexPath.row number (because I am using it in cellForRowAtIndexPath) like this:
let entry: AnyObject = city.cities[indexPath.row]
println(entry.name as String)
How could I make this code work?
First of all, a few comments.
There is no need for nested classes or even a custom class at all
Just use an array of Strings
add to array like this : array.append(Item)
Do not initialise as AnyObject in a language that is aware of types. (let entry: AnyObject = city.cities[indexPath.row])
In your example you have a collection of Strings so I would just use this:
var cities : [String] = []
cities.append("NY")
let city = cities[0] // NY
You also stated that you have a part of your code in a different file. I am assuming you want to have a method for fetching and storing the values. And a separate method to display them?
I would propose making two classes if you want to handle more than just a City Name and want to have access to the fetched data anywhere in your app.
Google Singleton for more info on how this works.
class City {
var name : String = ""
var geoLocation : CLLocationCoordinate2D?
// more attributes of your city object
init(name name_I: String) {
self.name = name_I
}
}
class Locations {
// the static part is shared between all instances of the Locations Class -> Google Singleton
static var cachedLocations : Locations = Locations()
var cities : [City] = []
init() {
}
}
// add a new city
let newCity = City(name: "NY")
Locations.cachedLocations.cities.append(newCity)
// in another class / file / viewcontroller ,.... get the cached city
let cachedCity = Locations.cachedLocations.cities[0]
You could add a class function to Locations to convert between a Dictionary and the City class. How to get a Dictionary from JSON
// class function is available without needing to initialise an instance of the class.
class func addCachedCity(dictionary:[String:AnyObject]) {
guard let cityName = dictionary["name"] as? String else {
return
}
let newCity = City(name: cityName)
cachedLocations.cities.append(newCity)
}
This would be used like this:
let cityDict : [String:AnyObject] = ["name":"LA"]
Locations.addCachedCity(cityDict)
Locations.cachedLocations.cities // now holds NY and LA
You could simply make your array an global array. You only have to define
your array out of the class. And then use the .append() function
let cities = []
class City {
class Entry {
let name : String
init(name : String) {
self.name = name
}
}
}
Related
I have created a class with some variables and have not initialized with any default value, all variables should be assigned when web service call occurs. So I have initialized the instance of the class and assigned the value to the variables.
Here I want to access these values to all class file throughout the project. Is it possible? I do not want to use any saving methods like core data and user defaults also codable local storage.
Please help me out with this? We tried to access the model class value in another view controller. But we get a nil value. Thanks in Advance.
//MARK: Shared Instance
static let sharedInstance = Singleton()
//MARK: Local Variable
var emptyStringArray : [String]? = nil
var completed : Bool!
var id : Int?
var title : String?
var userId : Int?
//MARK: Init Array
private init() {
}
init(Fromarray dictionary : [String:Any]) {
completed = dictionary["completed"] as? Bool
id = dictionary["id"] as? Int
title = dictionary["title"] as? String
userId = dictionary["userId"] as? Int
}
finally called in
class ViewController2: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let BoolValue = Singleton.sharedInstance.completed
print(BoolValue)
}
This is a very poor architectural decision.
Among the many the first problem here is that results of API calls are always asynchronous so you can't tell if your class have been properly initialized at the moment you use it's properties.
You create too much ambiguity by creating forced unwrapped optional that depends on network call. What if API call fails? What if internet connection is slow, how would you predict that your singleton is "fine" at this moment? For most of the cases you will be accessing nil and it will crash your app.
I'd suggest more reading on Singleton pattern (if it's necessary) and also on architectural patterns in iOS.
use different function to load data and call that after WebCall
func loadData(Fromarray dictionary : [String:Any]) {
completed = dictionary["completed"] as? Bool
id = dictionary["id"] as? Int
title = dictionary["title"] as? String
userId = dictionary["userId"] as? Int
}
call after web call completion
Singleton.sharedInstance.loadData(FromArray : YourDictoinary)
and acess anywhre throught project
let title = Singleton.sharedInstance.title
You need to keep a single object of your singleton class.
static let sharedInstance = Singleton()
It will create a object of your singleton class.
private init() { } or,
init(fromarray dictionary: [String:Any]) {
completed = dictionary["completed"] as? Bool
id = dictionary["id"] as? Int
title = dictionary["title"] as? String
userId = dictionary["userId"] as? Int
}
It will create another object of your singleton class, which will be differ form above.
If you need to access the data from your singleton class. Create your class like:
class Singleton {
static let sharedInstance = Singleton()
var emptyStringArray: [String]?
var completed: Bool?
var id: Int?
var title: String?
var userId: Int?
func initializeData(_ dictionary: [String:Any]) {
completed = dictionary["completed"] as? Bool
id = dictionary["id"] as? Int
title = dictionary["title"] as? String
userId = dictionary["userId"] as? Int
}
}
And use it like:
override func viewDidLoad() {
super.viewDidLoad()
// Initialize with data
Singleton.sharedInstance.initializeData(["completed": true, "id": 123, "title": "iOS Title", "userId": 572])
// Access data
let boolData = Singleton.sharedInstance.completed
print(boolData)
}
I have a class like
class Person {
var address:String
var number:String
var houseNo:String
var licenceNo:String
....
}
let jone = Person()
jone.number = "123456"
So in this i need to initialize the variable of person class one by one. And i have approx 30 variables in person class.
Is not there s simple way to do this ?
like I have all the keys coming from backend like "number = 123456". Is not there a way that i run a for loop and use something like.
for key in keys {
john."\(key)" = dict[key]
}
Is not there a way to shorten this lengthy procedure ?
You can try out this code
extension NSObject{
// fetch all class varible
func property() -> Mirror.Children {
return Mirror(reflecting: self).children
}
func propertyList() {
for (name, value) in property() {
guard let name = name else { continue }
print("\(name): \(type(of: value)) = '\(value)'")
}
}
}
Your class, set value like below code it's helpfull
class Person: NSObject {
var address:String = ""
var number:String = ""
var houseNo:String = ""
var licenceNo:String = ""
init(with response: [String: AnyObject]) {
for child in self.property() {
if let key = child.label, let value = response[key] {
self.setValue(value, forKey: key)
}
}
}
}
person.propertyList()
// Display all class property list
address: String = ''
number: String = ''
houseNo: String = ''
licenceNo: String = ''
Why don't use a Person method for load the backend response into a new Person object?
Somethind like that:
let jone = Person()
jone.loadDataFrom(response)
Or use a Person static method
let jone = Person.loadDataFrom(response)
static func loadDataFrom(response:Object) -> Person {
let p = Person()
...
set response data
...
return p
}
I have an array of struct elements that I would like to store globally so that I can access it in different classes without having to run the query that populates it over and over.
I have a struct:
struct collectionStruct {
var name : String
var description : String
var title : String
var image : PFFile
var id: String
}
and a variable:
var collectionArray = [collectionStruct]()
and some code to build the array:
for object in items {
let arrayName = object.object(forKey: fromName) as! String
let arrayDescription = object.object(forKey: fromDescription) as! String
let arrayTitle = object.object(forKey: fromTitle) as! String
let arrayImage = object.object(forKey: fromImage) as! PFFile
let arrayID = object.objectId as String!
collectionArray.append(collectionStruct(name: arrayName,
description: arrayDescription,
title: arrayTitle,
image: arrayImage,
id: arrayID!))
}
I was thinking of creating another struct to hold the array itself bt am a bit lost here. this is what I was thinking:
struct globalArray {
var collectionArray = [collectionStruct]()
}
but a probably way off
You should consider naming your struct CollectionStruct rather than collectionStruct - as that indicates it is a type. To access the array anywhere you could create a singleton. With a singleton, you ensure there is only one instance available by giving it a private constructor. Here is an example:
class Global {
private init() { }
static let sharedInstance = Global()
var collection = [CollectionStruct]()
}
To use it you would use the following:
Global.sharedInstance.collection
You can use singleton for global class that's able to be accessing from anywhere:
class GlobalArray {
static let shared = GlobalArray()
var collectionArray = [collectionStruct]()
}
and accessing like this to assign or read value:
GlobalArray.shared.collectionArray
You can just declare
var collectionArray = [collectionStruct]()
at the top level in any file (outside any object), and it will be available globally
e.g.
var collectionArray = [collectionStruct]()
class MyClass {
func printArray() {
print(collectionArray)
}
}
I just want to know the attributes datatype of a class has inner class objects while iterating.
Find the code mentioned below.
class myClass1: NSObject {
var name:String?
var id:Int32?
}
class myClass2:NSObject {
var sessionId:String?
var classObj:[myClass1]?
var item:Int?
}
let mirroredObject = Mirror(reflecting: myClass2())
var dictionary = [String:Any]()
for(index,attr) in mirroredObject.children.enumerated() {
if let property_name = attr.label {
let submirroredObj = Mirror(reflecting: property_name)
dictionary["\(property_name)"] = type(of: (attr.value)) as Any?
}
}
for (index,item) in dictionary.enumerated() {
print(item.value)
}
In the above code it will display the list of attributes of a classObject. here I don't know how to compare the listed attributes of a class.
Use this to get the type of the property:
attr.value.dynamicType
I'm receiving a JSON dictionary from a web service and I need to map the return values to existing values. Here's essentially what I'm trying to do:
class Contract {
var contractID: String?
var ebState: String?
var ibState: String?
var importerState: String?
var exportersBankRefNo: String?
var importersBankRefNo: String?
}
let contract1 = Contract()
contract1.contractID = "001"
let contract2 = Contract()
contract2.contractID = "002"
// This is the JSON return dictionary
let exportAppnStatusList: [[String: String]] = [["contractID":"001",
"ExporterBankRefNo":"ExporterBankRefNo001",
"ExporterBankState":"ACCEPTED",
"ImporterBankRefNo":"",
"ImporterBankState":"UNKNOWN",
"ImporterState":"UNKNOWN" ],
["contractID":"002",
"ExporterBankRefNo":"ExporterBankRefNo002",
"ExporterBankState":"ACCEPTED",
"ImporterBankRefNo":"ImporterBankRefNo002",
"ImporterBankState":"ACCEPTED",
"ImporterState":"UNKNOWN" ]]
I need to take the exportAppnStatusList and fill in the associated values in the existing contract1 and contract2, mapping by the contractID
This fills the contracts with available information, it ignores contracts where the id could not be found:
for contract in [contract1, contract2] {
if let contractDict = exportAppnStatusList.filter({$0["contractID"] == contract.contractID}).first {
contract.exportersBankRefNo = contractDict["ExporterBankRefNo"]
contract.ebState = contractDict["ExporterBankState"]
contract.importersBankRefNo = contractDict["ImporterBankRefNo"]
contract.ibState = contractDict["ImporterBankState"]
contract.importerState = contractDict["ImporterState"]
}
}
Why not generate the contract object by mapping over the array of dictionaries like this? You'll need to write a custom initializer that takes all these params
exportAppnStatusList.map { (dict:[Stirng:String]) -> Contract in
return Contract(contractID:dict["contractID"],
ebState:dict["ExporterBankState"],
ibState:dict["ImporterBankState"],
importerState:dict["ImporterState"],
exportersBankRefNo:dict["ExporterBankRefNo"],
importersBankRefNo:dict["ImporterBankRefNo"]
}
Try using this init (your class must inherit from NSObject):
init(jsonDict: [String: String]) {
super.init()
for (key, value) in jsonDict {
if class_respondsToSelector(Contract.self, NSSelectorFromString(key)) {
setValue(value, forKey: key)
}
}
}
Then you can do this:
exportAppnStatusList.forEach {
print(Contract(jsonDict: $0))
}