Simple Clarification Objects Swift Language - ios

I have a very simple question on something that I may have misunderstood.
I have two UIViews "A" and "B". If I write :
let A = UIView() // Or something else
let B = A
and then I change properties of B (for exemple the frame), will the properties of A change too ?
I though not, but I was animating a view, so I had the initial view and the final view. I created a transition view like this :
let transitionView = finalView
and then I changed the properties of transitionView, the position of a label for exemple.
When I added the final view at the end of the animation, the label was at the new position.
Why ? Thanks

In swift types are split in 2 main categories:
reference types
value types
Classes are reference types; structs (which include arrays and dictionaries), basic data types (int, float, string, etc.), and enums are all value types.
A value type is always passed by value, which means when assigning to a variable or passing to a function/method, a copy of the original data is created. There's an exception to this rule: a function/method can use the inout modifier on a value type parameter to have it passed by reference.
Note that the compiler and the runtime usually do optimizations, so a copy is not always created unless strictly needed - what's important is that we, as developer, know that we are working on a copy and not on the original data.
A reference type is always passed by reference, which means when assigning it to a variable or passing it to a function/method, a reference to the data and not the data itself is assigned/passed.
UIView is a class, so when you create an instance, assign it to a variable, then assign that variable to another variable, the reference to the instance and not the instance itself is assigned. Both variables point to the same UIView instance. Any change made to the instance is visible to all variables referencing that instance.
Suggested reading: Classes and Structures

Because B and A are not two views. They are references to the same UIView object.
That, in turn, is because class instances are passed as reference types in Swift.
See now my little essay on this topic here: https://stackoverflow.com/a/27366050/341994

Related

Should I use var or let for an object later mutated?

I have an iOS app that, upon startup, loads objects from persistent storage that will be manipulated later in the app. For example, on startup it loads patient profiles in an array. Does it matter if I define the items I add to the array as variables, versus constants, if they will be modified by the app later (say in a different View Controller)?
In my App Delegate, I load them like this:
func loadProfiles() {
var profileRecord: COpaquePointer = nil
if sqlite3_prepare_v2(db, "SELECT profilesid, objectSyncStatus, profileName, profileRelationship, profileFName, profileLName, profileAddress, profileCity, profileState, profileZip FROM profiles", -1, &profileRecord, nil) == SQLITE_OK {
if sqlite3_step(profileRecord) == SQLITE_ROW {
// Load profile stubs for each person
var newProfile = DBProfile(withDatabase: db, fromRecord: profileRecord, withLanguage: appLanguage, loadAllData: false)
patientProfiles.append(newProfile)
}
}
}
Of course, I get a warning that newProfile is not mutated, and it wants to change it to let newProfile = ... before it is added to the array. But, if I do that, will it become immutable later?
Thanks for the answers.
The compiler is actually really good at determining whether you should use let or var, and in this case, it is correct.
var should be used anywhere the data will be mutated. For example:
A struct value where the properties will be mutated
Pointers (like your COpaquePointer)
Instances of classes that will be reassigned to different class instances
let should be used anywhere the data will not be mutated. For example:
Constants
Values to be added to arrays, dictionaries, arguments to functions, etc.
Class instances where the instance will not be reassigned.
Note that for instances of classes, you can still modify the properties of the class even if it is defined as let. var should only be used in this case when the class itself will be reassigned.
In the case of your newProfile variable, during it's lifetime it is never mutated. The object is created, then immediately appended to your array. That array needs to be defined with var because it is mutated with that append, but newProfile never gets changed. You can change the value that was appended from newProfile through the array at a later date if you'd like because the patientProfiles array is mutable.
A good practice for when you are not sure whether to use let or var is to start with let and see if the compiler complains. If it does, then change it to var.
I see that you do not quite understand what is constant and how it works with value and reference types.
You can think of constant as glass box with lock and key.
Once you put something in box and lock it you threw away the key so you can see box contents (read properties and call non-mutating methods) but can not change it.
Words mutated and immutable can be only applied to value types because in case of value type the box holds value itself and if some method of value can change value then it must be marked with keyword mutating so it will not be visible through box glass.
In case of reference type the box holds reference to instance of type. If you define constant of reference type then you have box with reference. You can not change the reference, but you can read it and then go and find instance by that reference and do whatever you like with that instance.
In your case you define constant:
let newProfile = DBProfile(...)
and DBProfile is class (reference type).
You can not assign another reference to newProfile but you do whatever you like with object that referenced by newProfile. So you append it to patientProfiles array and you can get it later from this array and do what you want.

What must be accomplished in the implementation of an initializer?

What must be accomplished in the implementation of an initializer?
a. All properties need to be initialized with a value
b. All properties need to be explicitly assigned a value.
c. All non-Optional properties need to be initialized.
Sorry, that's incorrect.
Optionals need to be initialized as well.
d. The object needs to be created
What answer is correct and why?
In my opinion that is very confusingly stated question. Because what you as the developer have to do is Option c.
Take a look at this simple code example and the minimum init to be compilable
class SomeClass {
var a : AnyObject
var b : AnyObject?
var c : AnyObject!
var d = ":)"
init() {
a = ""
print("initialized")
}
}
The swift docu states
Classes and structures must set all of their stored properties to an appropriate initial value by the time an instance of that class or structure is created. Stored properties cannot be left in an indeterminate state.
You can set an initial value for a stored property within an initializer, or by assigning a default property value as part of the property’s definition. These actions are described in the following sections.
Option d. is imho non-sense since the object creation is handled by the underlying runtime environment and not via the initializer.
Now b. and a. remain with the tiny difference in wording explicitly assigned vs. initialized. I would therefore discard Option b because the b and c variable do not need any explicit value, the implicit nil is perfectly fine for the time (reading c will not work yet though)
Therefore my answer choice would be Option a. After the init method all properties need to have some specific value. Some of them explicitly in the init function, some of them implicitly.
tl;dr:
my final answer is Option a.

What's the different between these properties?

I have created a class RootView with two properties, declared in different ways. Now I want to know what the difference between those two declarations is?
class RootView: UIViewController {
// MARK: - Variables
var rightMenu: RightMenu = RightMenu()
let right = RightMenu()
}
Please guide me about difference between right and rightMenu?
Both are of same type, but here below are few points that will tell when you need Type Annotation and when not.
Here are few concepts.
Your rightMenu is a variable, you reassign a value of same type at alter point, where as right is a constant, you can not reassign a new value.
Swift introduced type inference concept, where if you assign a value(literals) with out providing type, it will directly determine the the type for you. So need to provide explicitly type for it. Here your both rightMenu and right are of same type.
Ideally no need to provide explicitly type if you are assigning initial value to a variable at the time of declaration.
a) var myClass: MyClass!
Here you need to provide type, because no intial value is provided and you want to assign value to it at later point.
b) var myClass = MyClass()
Here no need, because you provided a initial value and Swift compiler will automatically determine the type for it.
In Swift providing/declaring type for a variable or constant after : symbol is called Type Annotation. For more details, see Apple documentation
The only difference is the mutability of those two variables. You can change rightMenu because it's mutable. However, right is not mutable. It means that right is a constant.
From the syntax prospectives, you don't necessarily to add :RightMenu when you declare rightMenu. Like you declare right, compiler will infer the object as type of RightMenu. But, when you want only to declare something without initializing it. You probably need to use :<type>? to tell the compiler that the type of this ivar and the value might be missing.

How to pass reference types by value?

I just started a question a few minutes ago were I learned, that class instances in swift are reference types. However as I asked how to pass an instance as copy then or just make a copy inside a function nobody seems to know for sure. So my question is:
Is it possible to pass a class object to a function by value?
If yes, how to do so and if no, how can I work with a copy then?
It is not possible to pass class objects in Swift by value. What is more, there is no general way of making copies of objects, so you need to provide e.g. appropriate initialiser yourself.
Value objects and reference objects serve different purposes. Asking how to pass a reference object by value is just absolutely pointless. However, a lot of the time you will pass immutable objects, and that means the reference to the object is the value.
By the way: You don't mean "class objects". You mean "instances of a class". In Objective-C, classes are themselves objects. For example, you send the alloc message to a class object.
How to pass reference types by value?
The answer to this question as phrased is you just pass it, by value. It works the exact same way for reference types and value types. Any parameter that is not marked inout in Swift is pass-by-value.
The value of a reference type variable is a reference, which points to an object. When you pass a reference by value, the receiving function receives a copy of this reference, which points to the same object.
Upon further reading of your question, it appears that you are not asking about the passing of reference types at all. Rather, you are asking about the copying of objects. When you wrote "reference type" what you really meant is something like an "object type", something whose value is an object, which when passed by value results in a copy of the object.
Swift has no "object types"; just like Objective-C and Java do not have "object types". It's impossible to have a variable whose value "is an object"; you can only have a variable whose value is a reference that "points to an object". You manipulate objects through these references. There is no syntax in the language to "dereference" a reference to the object it points to.

Passing Arrays/Objects between ViewControllers in Swift

Following on from this question: Is there a reason that Swift array assignment is inconsistent (neither a reference nor a deep copy)? -
I have been playing with passing objects in Swift and noticed some strange results.
To clarify the kind of behaviour i'm used to (prior to Swift) would be that of Objective C.
To give an example in one of my Applications (written in Obj C) I have the concept of a 'notification list'. - really just an array of custom objects.
In that App I often pass my global array of 'notifications' to various viewControllers which provide a UI to update the list.
When I pass the global array to a child viewController I assign it to a local array variable in the recipient object. Then, simply by updating/changing the local array these changes are reflected in the global array on the rootViewController. I understand this behaviour is implicit in Objective C as objects as passed by reference, but this is really handy and I have been trying to replicate this behaviour in Swift.
However whilst I have been rewriting my App in Swift I've hit a wall.
I first tried to pass a Swift array of strings (not NSMutableArray) from the rootViewController to a child viewController (as described above).
Here is the behaviour when passing in the array of Strings the child viewController:
I Pass in:
[Bill, Bob, Jack] and then assign this passed array to a local array for local modification,
Then I append the String “Frank” to the local array
The results are:
Local array = [Bill, Bob, Jack, Frank]
Global array = [Bill, Bob, Jack]
No changes to the local array are reflected back to the global array. - The SAME result occurs for a change of element (without changing the length of the array.)
I have also tried the above experiment with a more real world example - passing in an array of my custom 'notification' objects to a child viewController. The SAME result occurs with none of the changes to the locally assigned array of custom objects being reflected to the original global array that was passed in.
This behaviour is not desirable to me, I assume the best practice here is to use delegate protocols to pass the modified array (or whatever object) back to the parent object and then to manually update the global array?? - if so this creates quite an extra workload over the Objective C style behaviour.
Finally I did try the inout keyword, which effectively lets you directly modify the function parameter var thats passed to the destination object.
Changes are reflected back to the global array (or object) However the problem is, if the input parameter is assigned to a local variable (to edit outside of scope of the init function) changes to the local variable are still not reflected in global scope.
I hope the above makes sense - It's really stifling my productivity with Swift.
Am I missing something or is this schizophrenic behaviour expected?
If so what is best practice on passing modified data back, delegates?
The linked question provides the answer - it is for performance.
The behaviour may not be desirable for you, but I would say that relying on side-effects from calling methods to modify parameters is the behaviour that is not considered desirable - particularly in a multi-threaded, multi-core environment where data structures can be corrupted.
A design that relies on side-effects is flawed, in my opinion.
If functions need to modify the "global" then they should either return the new value, or if that isn't possible then you should wrap your array inside an object and provide appropriate functions to manipulate the data values.
Swift blurs the lines between intrinsic and object somewhat with arrays, which makes it a little confusing - in Objective-C an NSMutableArray is an object so it always passed by reference.
For notifying other objects that the data has changed you can use an observer pattern. The typical delegate pattern only has a single registered delegate - With an observer pattern you can have multiple registered observers.
You can do this through NSNotificationCenter or an array of "delegates". The former has the advantage of decoupling the code more than delegation
Why don't you create a Model class that contains the array as a var. Add methods to the Model class to manipulate the array and store the new instance in the property. Create a single instance of the Model class at startup and pass it to the view controllers. They all access the array through the Model or through methods in the Model class. The behavior of Swift (where it copies the array on change of size) will be hidden from all of the view controllers.

Resources