Populate Class Properties via 1 line within a for loop? - ios

Let's say I have a class that has 10 properties. I have an XML response (AEXMLDocument in this case) where the element tags match the property names exactly. Is there a way I could populate the values in a for loop rather than writing out 10 lines of code? I used ***property.name**** to show where I would like to put these variables. That part is not actually in the code.
class User(){
var firstName = String()
var lastName = String()
var middleName = String()
...
var property10 = String()
}
func populateUser (xml: AEXMLDocument) -> User{
var returnUser = User()
for property in xml.root["SOAP-ENV:Body"]["ns1:getUserResponse"]["return"].children{
returnUser.***property.name*** = property.value
}
return returnUser

You can use setValue(_, forKey:) method as long as you subclass from NSObject.

If the class inherits from NSObject, you can use key-value coding:
returnUser.setValue(property.value, forKey: property.name)
Be careful with this though. Anyone who can modify the XML sent to your app can modify any property on the User object.

Related

Why I can't change value in nested Models?

I have 2 class , First class has a property which inheritance from second class
class FirstModel{
var firstType : Secondmodel?
}
class Secondmodel{
var secondType : Int?
}
Now I want to set a value to secondType so I code
var Modelll = FirstModel()
Modelll.firstType?.secondType = 100
When I try to read this property with print(Modelll.firstType?.secondType) it return nil
So first question is why I couldn't read this
But I try to do this
var Modelll = FirstModel()
var ModelSecond = Secondmodel()
ModelSecond.secondType = 100
Modelll.firstType = ModelSecond
print(Modelll.firstType?.secondType)
It works perfectly , printed out Optional(100) I really dont understand whats going on behind the scene. Can anyone explain this?
First of all, all variables and constant should be named with lowercased symbol. With Uppercased only names of classes, structs, protocols, enums etc
You problem is that when You init FirstModel, firstType variable is nil by default
var model = FirstModel()
print(model.firstType) //prints nil
so You need to do
var model = FirstModel()
model.firstType = SecondModel() //use camel case in naming
model.firstType?.secondType = 100
print(model.firstType?.secondType) // prints 100
Ammm.. Because you don't initiate firstType with an instance in your first try.
You can add something like this
class FirstModel{
var firstType : Secondmodel?
init() {
self.firstType = Secondmodel()
}
}
But this is not exactly how things should be done. Here is not a problem of nesting, you just don't give a value in firstyType property.
The best case should be like:
class Secondmodel{
var secondType : Int?
init(secondType: Int) {
self.secondType = secondType
}
}
var modelll = FirstModel()
modelll.firstType = SecondModel(secondType: 100)
You should read more about OOP.
..and objects should not be named with capital letters

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

Using Generic in iOS

I am new to iOS development . I wanted to create a dictionary which is looks like
var userInformation: UserInformation = UserInformation()
var genericDictionary: Dictionary<Int,userInformation> = [Int:userInformation]()
here ,userInformation is an object of UserInformation class .
class UserInformation{
var name:String?
var phonenumber:String?
init(_ name:String ,_phoneNumber:String){
self.name = name
self.phoneNumber = phoneNumber
}
and lastly i tried genericDictionary.append(). i wanted to store name and phone number here. i don't know how it works!
i tried , but it shows various kinds of error. is it possible to do this ?
Problem is in declaration of dictionary with value type you are specifying the object that you have created instead of its type, means it should be UserInformation class type instead of instance of it userInformation. Try like this way.
var genericDictionary = [Int:UserInformation]()
Edit: With latest edit of your question I thin'k you are looking for array not dictionary, if it is true try like this way.
var array = [UserInformation]()
array.append(userInformation)
Do like this :
var genericDictionary : [Int : UserInformation] = [:]
You are declaring the dictionary using a variable instead of the class. Instead of userInformation, you need to use UserInformation like this:
var genericDictionary: Dictionary<Int,UserInformation> = [Int:UserInformation]()

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.

iOS: setter in an object class with external parameter

I have this object class
class City {
var name:String
init(name: String) {
self.name = name
}
var video:String?
var description:String?
var image_array:NSArray?
}
in this class there is a property called image_array, and I want to assign it an NSArray as you can read.
But in this case I have to pass at this property a String that I should transform into an array
example:
The string is "img1.jpg,img2.jpg,img3.jpg"
then I use
let fullNameArray = fullName.componentsSeparatedByString(",")
and I obtain an NSArray
So what's the way to pass this String to the setter for image_array inside City object?
Then inside the setter to transform it into an array... I hope that it's clear.
You wouldn't, you need to either 1. transform it into an array and then pass it, or 2. add a different method which takes a string, transforms it and then calls the array setter.
Option 1. is better as it maintains a sane interface and doesn't pollute the class interface with crud from other classes.
If you really want to do it this way in order to write string from array use
var myString:String = array.description.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: "[]"))
and to get array back from string
var array:[String] = myString.componentsSeparatedByString(", ") //dont forget space character

Resources