How to get method for class in Swift - ios

I have a class:
class myObject: NSObject {
dynamic var objectId : String?
dynamic var name : String?
dynamic var lastName : String?
dynamic var age : String?
}
In my other class I am getting the value of this class's property:
self.myArray.append(myObject.name!)
I can get the value of myObject.name by adding .name but what if there will be hundreds of properties in my myObject class? For that I want to create a method which can return the properties of my class using a variable:
let myVar = "name"
self.myArray.append(myObject.myVar)
It should append the values of property name, but I am getting an error:
value of myObject has no member `myVar`
and I know why I am getting the error.
How can I get access to properties of my class using a variable? Something like :getValue(String) should return that property of my class.

You should also have a look at NSMutableDictionary, here's a quick example which shows how it works
// initialise a dictionary
var dict = NSMutableDictionary(objects: ["first", "second", 42], forKeys: ["String1", "String2", "Int1"])
// add a new attribute
dict.addEntriesFromDictionary(NSDictionary(object: "New thing", forKey: "String3") as [NSObject : AnyObject])
// access the data
let firstString = dict.valueForKey("String1")
let firstInt = dict.valueForKey("Int1")
// update the data
dict.setValue(99, forKey: "Int1")
let newValue = dict.valueForKey("Int1")

I can be wrong, but as I've already said in a comment, it would be better to use Dictionary and store values in it. Also if you want to access some values with a dot-notation, but still be able to get them by string, you can just create a property and override setter and getter
class MyClass {
var properties = [String: AnyObject]()
var someProperty: String? {
get {
return properties["someProperty"] as? String
}
set {
properties["someProperty"] = newValue
}
}
This way you are able to access value of someProperty both by object.someProperty and object.properties["someProperty"]

You can do it making array of object like following
var arrayOfObjects = [myObject]
and then set an objects values
var firstObject:myObject
myObject.name = "Your name"
myObject.age = "Your age"
...
then append first object to arrayOfObjects
arrayOfObject.append(firstObject)
and you can access it
print("First Object's name: \(arrayOfObjects[0].name)")

Related

What's the difference between : and = in swift

Sorry if the title is rather confusing, but I'm curious to know the difference between these two lines:
var title = String()
var title: String
Is one being initialized and one only be declared? Which is more correct?
For example, if I have a struct should I use one of the other?
So the reason I ask this is because I'm learning about how to grab some JSON from a url and then display it in my app. One of the new ways of doing so is using Decodable. So, I have a struct in a model class like so:
struct Videos: Decodable {
var title = String()
var number_of_views : Int
var thumbnail_image_name: String
var channel: Channel
var duration: Int
}
In another class I have this:
URLSession.shared.dataTask(with: url){(data,response,error) in
if(error != nil){
print(error!)
return
}
guard let data = data else { return }
do{
self.Videos2 = try JSONDecoder().decode([Videos].self, from: data)
//self.collectionView?.reloadData()
}catch let jsonErr{
print(jsonErr)
}
}.resume()
So, should I declare or initialize the variables in my struct? I'm assuming I should just declare them like so:
var title: String?
Would that be the correct syntax in my struct?
UPDATE:
I understand this question was more broad then I originally proposed it to be. I'm sorry about that, but thank you so much for all your great answers that clarified a lot up for me.
The difference is that : defines the type of your variable, whereas = assigns an actual value to the variable.
So:
var title = String()
This calls the initializer of the String type, creating a new String instance. It then assigns this value to title. The type of title is inferred to be String because you're assigning an object of type String to it; however, you could also write this line explicitly as:
var title: String = String()
This would mean you are declaring a title variable of type String, and assigning a new String to it.
var title: String
This simply says you're defining a variable of type String. However, you are not assigning a value to it. You will need to assign something to this variable before you use it, or you will get a compile error (and if this is a property rather than just a variable, you'll need to assign it before you get to the end of your type's init() method, unless it's optional with ? after it, in which case it gets implicitly initialized to nil).
EDIT: For your example, I'd probably declare all the variables using let and :, assuming that your JSON provides values for all of those properties. The initializer generated by Decodable should then set all the properties when you create the object. So, something like:
struct Videos: Decodable {
let title: String
let number_of_views : Int
let thumbnail_image_name: String
let channel: Int
let duration: Int
}
This initializes a value
var title = String()
This declares a value but does not initialize it
var title: String
If you attempt to use the latter, such as print(title), you will get a compiler error stating Variable 'title' used before being initialized
It does not matter whether the value is a class or a struct.
The = operator is the assignment operator, it assigns a value to the object on the left of the =
Typically, class or struct properties are declared but not initialized until the init() is called. A simple class might be
class MyClass {
let myProperty: String
init(aString: String) {
self.myProperty = aString
}
}
Whereas inside the scope of a function you may declare a local variable that only lives inside the scope of the function.
func doSomethingToAString(aString: String) -> String {
let extraString = "Something"
let amendedString = aString + extraString
return amendedString
}
In your specific example, the struct synthesizes an initializer that will allow you to initialize the struct with all the values needed to fill your properties. The initializer generated by Decodable should then set all the properties when you create a Videos struct, you will do it something like:
let aVideos = Videos(title: "My Title", number_of_views: 0, thumbnail_image_name: "ImageName", channel: Channel(), duration: 10)
Is one being initialized and one only be declared?
Yes, meaning that the declared cannot be used. If you tried to set a value for it, you would get a compile-time error:
variable 'title' passed by reference before being initialized
Which is more correct?
There is no rule of thumb to determine which is more correct, that would be depends on is there a need to initialize title directly.
On another hand, when it comes to declare properties for a class, saying var title = String() means that you are give title an initial value ("") which means that you are able to create an instance of this class directly, example:
class Foo {
var title = String()
}
let myFoo = Foo()
However, if title declared as var title: String, you will have to implement the init for Foo:
class Foo {
var title: String
init(title: String) {
self.title = title
}
}
let myFoo = Foo(title: "")
Also, you have an option to declare it as lazy:
lazy var title = String()
which means:
A lazy stored property is a property whose initial value is not
calculated until the first time it is used. You indicate a lazy stored
property by writing the lazy modifier before its declaration.
Properties - Lazy Stored Properties

How can I find the type of a property dynamically in swift (Reflection/Mirror)?

So let's say I have a class like this:
class Employee: NSObject {
var id: String?
var someArray: [Employee]?
}
I use reflection to get the property names:
let employee = Employee()
let mirror = Mirror(reflecting: employee)
propertyNames = mirror.children.flatMap { $0.label }
// ["businessUnitId", "someArray"]
so far so good! Now i need to be able to figure out the type of each of these properties, so if I do the employee.valueForKey("someArray"), it won't work because it only gives me the AnyObject type. What would be the best way to do this? Specially for the array, I need to be able to dynamically tell that the array contains type of Employee.
You don't need to inherit from NSObject (unless you have a good reason to).
class Employee {
var id: String?
var someArray: [Employee]?
}
let employee = Employee()
for property in Mirror(reflecting: employee).children {
print("name: \(property.label) type: \(type(of: property.value))")
}
Output
name: Optional("id") type: Optional<String>
name: Optional("someArray") type: Optional<Array<Employee>>
This also works with Structs
If you are inheriting from NSObject, you can use some of the methods provided by NSCoding and the Objective-C runtime:
let employee = Employee()
employee.someArray = []
employee.valueForKey("someArray")?.classForCoder // NSArray.Type
employee.valueForKey("someArray")?.classForKeyedArchiver // NSArray.Type
employee.valueForKey("someArray")?.superclass // _SwiftNativeNSArrayWithContiguousStorage.Type
employee.valueForKey("someArray")!.dynamicType

Cannot access object inside of array (Swift)

I have created a class as such:
class Task {
var name:String
var description:String
var date:NSDate
var taskCompleted:Bool
init(name:String, description:String,date:NSDate, taskCompleted:Bool){
self.name = name
self.description = description
self.date = date
self.taskCompleted = taskCompleted
}
}
I then create a new object like so:
let newTask:AnyObject = Task(name: taskName.text!, description: descriptionInput.text, date: datePicker.date, taskCompleted: false)
Later on I add the object to an array:
var tasks = [AnyObject]()
tasks.append(newTask)
However, when I try to access the object again like so I get an error:
print(tasks[0].name)
ERROR: unexpectedly found nil while unwrapping an Optional value
Your array is of type [AnyObject]. If you want to avoid using as keyword, you should make it of type [Task] because AnyObject doesn't necesseraly have a name property. This is why it yells found nil while unwrapping an Optional value.
Try this :
let newTask:Task = Task(name: taskName.text!, description: descriptionInput.text, date: datePicker.date, taskCompleted: false)
var tasks = [Task]()
tasks.append(newTask)
print(tasks[0].name)
Like Lindsey said, you can use the as keyword if you want to have different types of objects in it but I don't think that is what you want.
In your current code tasks[0] is of type AnyObject which does not have a "name" property. Try changing:
print(tasks[0].name)
to
print((tasks[0] as! Task).name)
in order to change tasks[0] from AnyObject to Task.
Currently when you access a task from your array you get back an AnyObject which knows nothing about your name attribute.
You can do one of two things depending on what you are trying to accomplish
You can set your array to be of type [Task] not AnyObject.
Cast the AnyObject to Task when retrieving it from array. (task[0] as! Task).name

Sorting array of custom objects by its variable

I've created a custom class to hold image and its string(its name)
class Countries: NSObject {
var countryName : String
var countryFlag : UIImage
init(countryName: String, countryFlag: UIImage) {
self.countryName = countryName
self.countryFlag = countryFlag
super.init()
}
}
I declared the class
var myList: Array<Countries> = []
And add each country info to the array
let image = UIImage(data:imageData!)
let dd = Countries(countryName: object["CountryName"] as! String, countryFlag: image!)
self.myList.append(dd)
I tried below code to sort the array but doesn't work;
self.myList.sortInPlace({ $0.countryName < $1.countryName })
Does anybody has idea how can I sort my array according to above code?
You can sort an array like this using -sortUsingComparator:, which you pass a block into. The block takes the two objects you want to compare and returns a NSComparisonResult which is your comparison of the two. You could provide a block that uses countryName.
You could alternatively use -sortUsingDescriptors: and pass in a NSSortDescriptor that looks at the countryName field.

swift access property of an object in Array, returns nil

I have been learning the swift language. I setup this vocabulary class and using this class to generate a new object "newWord". I put this object into a new Array "vocabularyListb". When I try to get the newWord.name property from the array, it returns "nil". So the question is how can I access the property of an Object that resides in an Array?
class vocabulary{
let name:String
init(name: String){
self.name = name
}
}
let vocabularyList1a = ["instigate", "constitution", "bellow", "jargon", "term"]
var vocabularyList1b = [AnyObject]()
var newWord = vocabulary(name: vocabularyList1a[0])
newWord.name
vocabularyList1b.append(newWord)
vocabularyList1b[0].name
At the moment you instantiate your vocabularyList1b as [AnyObject]. But you actually want to have an array of vocabulary objects.
So you will have to change :
var vocabularyList1b = [AnyObject]()
To:
var vocabularyList1b = [vocabulary]()
After that you can access the name variable.

Resources