Store array globally in struct or other method - ios

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)
}
}

Related

Array in object from data model comes nil

I have a model class called Coupon and it has an array of objects called Array!
When I create an object from from Coupon class the array inside of this object comes nil and it gets an error. What am I doing wrong?
class Coupon {
private var _date: String!
private var _editor: String!
private var _predictions: Array<Prediction>?
var date: String {
get {
return _date
}
}
var editor: String {
get {
return _editor
}
}
var predictions: Array<Prediction>? {
get {
return _predictions
}
set {
self._predictions = predictions
}
}
}
And the controller is as follows: c.predictions![0] gives nil error
let ref = DataService.ds.REF_COUPONS.queryOrdered(byChild: "date")
ref.observe(.childAdded, with: { (snapshot) in
if let couponDict = snapshot.value as? Dictionary<String, AnyObject> {
let c_key = snapshot.key
let c = Coupon(couponKey: c_key, couponData: couponDict)
let childSnapShot = snapshot.childSnapshot(forPath: "predictions")
if let snapshots = childSnapShot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshots{
let p_key = snap.key
let p = Prediction(predictionKey: p_key, predictionData: snap.value as! Dictionary<String, AnyObject>)
self.predictions.append(p)
c.predictions![0] = self.predictions[0] <--- ERROR LINE
}
}
self.coupons.append(c)
}
self.couponsTableView.reloadData()
})
Because it's value is nil by default. So predictions! will result in trying to unwrap an optional whose value is nil kind of error.
You should create new array there:
c.predictions = [self.predictions[0]]
Also there is no need for backing fields in swift. Your Coupon class can be reduced to:
class Coupon {
private(set) var date: String!
private(set) var editor: String!
var predictions: Array<Prediction>?
}
private(set) means that the value can only be set within this class.
The definition line of predictions var predictions: Array<Prediction>? can be replaced to have default value of empty array:
class Coupon {
private(set) var date: String!
private(set) var editor: String!
var predictions: [Prediction] = []
}
[Prediction] is same as Array<Prediction>
Once it has default value of empty array instead of creating new array you can safely append to it:
c.predictions.append(self.predictions[0])
Also note that your code c.predictions[0] = self.predictions[0] would work never even in this case because the array is defaulted to empty has not 0th element.
When you create the class Coupon with let c = Coupon(couponKey: c_key, couponData: couponDict) your array is not initialize, so that's normal to have an error when you are trying to use it in the line c.predictions![0] = self.predictions[0] <--- ERROR LINE, your object Coupon you could initialize the array predictions as an empty array like this
class Coupon {
private var _date: String!
private var _editor: String!
private var _predictions = [Prediction]()
Element in predictions array at index 0 doesn't exist, so you can't replace it with new element. I suggest you to replace _predictions array with empty predictions array
var predictions = [Prediction]()
then you can append new element to this array like this:
c.predictions.append(self.predictions[0])
Also in your case there is no need to use property with getter and setter and you can also use struct instead of class
struct Coupon {
var date: String
var editor: String
var predictions = [Prediction]()
// your convenience init
}

How to access model class values in another controller using singleton in swift?

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)
}

Comparing the datatype of an inner class attributes to its corresponding datatype

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

Adding elements to array from another class

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
}
}
}

Filter NSMutableArray data by value into object in Swift

I have this problem
I'm using Swift 2.0 in my project for iOS 9. I've created an object like this:
public class element_x: NSObject{
var name: String!
var description_element: String!
}
So, In a method I declare two NSMutableArray: 1) for all data and 2) for filter data, like this:
var original = NSMutableArray()
var filtered = NSMutableArray()
And during the process I populate this NSMutableArray like this:
let custom_object = element_x()
self.original.addObject(custom_object);
My question is: how can I filter original array by name value and saved in filtered array?
You don't have to use NSMutableArray. The native Array type in Swift is very capable. You can declare it mutable with var (equivalent to NSMutableArray) or constant with let (same as NSArray):
public class element_x: NSObject{
var name: String!
var description_element: String!
}
// Declare an array containing elements of element_x type
var original = [element_x]()
var filtered = [elememt_x]()
let custom_object = element_x()
self.original.append(custom_object)
// Find all elements with name == "david"
self.filtered = self.original.filter { $0.name == "david" }

Resources