If obj not exist obj? generate a nil so obj?.attr too.
If obj is nil then obj!.attr crashes.
But if I am sure obj at that certain point of the code always exist, than for me it seems it is independent which one to use. Am I right? What coding styles do you use?
In my very own opinion, if you're really sure that obj exists, you can use ! or ? either. They produce the same effect on an existing object. The only issue is the compiler: sometimes it's fine to use ! instead of ?, sometimes not.
Anyway, if you want to read further on this, give a chance to the free book by Apple "The Swift Programming Language": these things are very well explained there!
If obj exists, obj?.attr returns an optional type even if attr is not an optional. On the other hand, obj!.attr will be whatever type attr is, so no additional unwrapping is needed if attr is a non-optional.
Consider this example:
class Person {
var age = 37
}
var fred: Person? = Person()
let ageNextYear = fred?.age + 1 // error: value of optional type Int? not unwrapped
let ageLastYear = fred!.age - 1 // this works
You use ? when you create a variable with out giving it a value, meaning it can exist and be used in an unitialized state. And as long as it is not initialized it has no type associated to it.
It has nothing do with the value being nil or not.
As Swift is type safe it requires all variables and constant to always hold a value by default, meaning they have a type. So defining something with ? or ! puts a wrapper around it.
enum Optional {
case None
case Some(T)
}
As you see it either has a type or not. Being nil (if possible for a type) or not has not much to do with it. But everything that does not have a type associated is usually nil.
When you then deal with the value of a variable that was declared as being optional, you need to unwrap it by using ! or else you would use the enumeration showed above.
Unwrapping means that you can assert that it does hold a value meaning it has a type. It takes it out of the enumeration and presents the value it has as a type.
Regarding coding style you usually only need to declare something as ? when you work with C or Objective-C APIs. In pure Swift you will usually not declare something as being optional.
You might need to use ! even in pure swift when something might not be defined. For example you have multi-dimensional array that were initialized as being empty. This is because of how Swift currently handle true multi-dimensional objects where the higher dimensions are implicit optionals.
TL;DR: Don't use ? at all unless you are forced to when dealing with C/Obj-C APIs. When using a value of a variable declared with ? always use ! to refer to the value and never ?.
Some links that explains what happens in more detail:
http://www.drewag.me/posts/what-is-an-optional-in-swift
http://www.drewag.me/posts/uses-for-implicitly-unwrapped-optionals-in-swift
Related
I'm really new to Swift and I just read that classes are passed by reference and arrays/strings etc. are copied.
Is the pass by reference the same way as in Objective-C or Java wherein you actually pass "a" reference or is it proper pass by reference?
Types of Things in Swift
The rule is:
Class instances are reference types (i.e. your reference to a class instance is effectively a pointer)
Functions are reference types
Everything else is a value type; "everything else" simply means instances of structs and instances of enums, because that's all there is in Swift. Arrays and strings are struct instances, for example. You can pass a reference to one of those things (as a function argument) by using inout and taking the address, as newacct has pointed out. But the type is itself a value type.
What Reference Types Mean For You
A reference type object is special in practice because:
Mere assignment or passing to function can yield multiple references to the same object
The object itself is mutable even if the reference to it is a constant (let, either explicit or implied).
A mutation to the object affects that object as seen by all references to it.
Those can be dangers, so keep an eye out. On the other hand, passing a reference type is clearly efficient because only a pointer is copied and passed, which is trivial.
What Value Types Mean For You
Clearly, passing a value type is "safer", and let means what it says: you can't mutate a struct instance or enum instance through a let reference. On the other hand, that safety is achieved by making a separate copy of the value, isn't it? Doesn't that make passing a value type potentially expensive?
Well, yes and no. It isn't as bad as you might think. As Nate Cook has said, passing a value type does not necessarily imply copying, because let (explicit or implied) guarantees immutability so there's no need to copy anything. And even passing into a var reference doesn't mean that things will be copied, only that they can be if necessary (because there's a mutation). The docs specifically advise you not to get your knickers in a twist.
Everything in Swift is passed by "copy" by default, so when you pass a value-type you get a copy of the value, and when you pass a reference type you get a copy of the reference, with all that that implies. (That is, the copy of the reference still points to the same instance as the original reference.)
I use scare quotes around the "copy" above because Swift does a lot of optimization; wherever possible, it doesn't copy until there's a mutation or the possibility of mutation. Since parameters are immutable by default, this means that most of the time no copy actually happens.
It is always pass-by-value when the parameter is not inout.
It is always pass-by-reference if the parameter is inout. However, this is somewhat complicated by the fact you need to explicitly use the & operator on the argument when passing to an inout parameter, so it may not fit the traditional definition of pass-by-reference, where you pass the variable directly.
Here is a small code sample for passing by reference.
Avoid doing this, unless you have a strong reason to.
func ComputeSomeValues(_ value1: inout String, _ value2: inout Int){
value1 = "my great computation 1";
value2 = 123456;
}
Call it like this
var val1: String = "";
var val2: Int = -1;
ComputeSomeValues(&val1, &val2);
The Apple Swift Developer blog has a post called Value and Reference Types that provides a clear and detailed discussion on this very topic.
To quote:
Types in Swift fall into one of two categories: first, “value types”,
where each instance keeps a unique copy of its data, usually defined
as a struct, enum, or tuple. The second, “reference types”, where
instances share a single copy of the data, and the type is usually
defined as a class.
The Swift blog post continues to explain the differences with examples and suggests when you would use one over the other.
When you use inout with an infix operator such as += then the &address symbol can be ignored. I guess the compiler assumes pass by reference?
extension Dictionary {
static func += (left: inout Dictionary, right: Dictionary) {
for (key, value) in right {
left[key] = value
}
}
}
origDictionary += newDictionaryToAdd
And nicely this dictionary 'add' only does one write to the original reference too, so great for locking!
Classes and structures
One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference.
Closures
If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles
ARC(Automatic Reference Counting)
Reference counting applies only to instances of classes. Structures and enumerations are value types, not reference types, and are not stored and passed by reference.
Classes are passed by references and others are passed by value in default.
You can pass by reference by using the inout keyword.
Swift assign, pass and return a value by reference for reference type and by copy for Value Type
[Value vs Reference type]
If compare with Java you can find matches:
Java Reference type(all objects)
Java primitive type(int, bool...) - Swift extends it using struct
struct is a value type so it's always passed as a value. let create struct
//STEP 1 CREATE PROPERTIES
struct Person{
var raw : String
var name: String
var age: Int
var profession: String
// STEP 2 CREATE FUNCTION
func personInformation(){
print("\(raw)")
print("name : \(name)")
print("age : \(age)")
print("profession : \(profession)")
}
}
//allow equal values
B = A then call the function
A.personInformation()
B.personInformation()
print(B.name)
it have the same result when we change the value of 'B' Only Changes Occured in B Because A Value of A is Copied, like
B.name = "Zainab"
a change occurs in B's name. it is Pass By Value
Pass By Reference
Classes Always Use Pass by reference in which only address of occupied memory is copied, when we change similarly as in struct change the value of B , Both A & B is changed because of reference is copied,.
I know the recommended way in Swift is to use:
class Address {
var firstLine : String?
var secondLine : String?
}
but sometimes I see other developers write their code this way:
class Address {
var firstLine : String = ""
var secondLine : String = ""
}
Is this the unrecommended way because whenever you have nil you will just crash and there's no outlet for your to recover. Is that right? Or there are some use cases where using non-optionals with default can be good. If so then where?
I saw this other question which is asking about efficiency rather than which better suits your needs. I'm looking for an answer where it says "This is a good place to use non-optionals and this is a good place to use optionals". Sometimes I see folks just dump optionals everywhere and it makes me think do we not ever need non-optionals? Sometimes I see people trying to avoid optionals as much as possible and just code in an Objective-C kind of style.
The above question's answer doesn't represent a valid case for where non-optionals are good. It's mute about that. As for choosing optionals: I'm guessing for models which get populated by network calls, optionals are the right choice, because you don't know whether it's nil or not.
The choice depends on what you model.
If a property of the object that you model may be absent completely, e.g. a middle name, a name suffix, an alternative phone number, etc., it should be modeled with an optional. A nil optional tells you that the property is not there - i.e. a person does not have a middle name or an alternative phone number. You should also use optional when you must distinguish between an empty object and a missing object.
If a property of the object must be set, and has a meaningful default, use an non-optional with a default:
class AddressList {
var addresses : [Address]
var separator : String = ";"
...
}
If users of your class need to change the separator, they have a way to do that. However, if they do not care about the separator, they can continue using the default without mentioning it in their own code.
Well you should use optionals if you think that the variable might not have a value. But if you're really sure that it's gonna have a value then you don't need to use them.
So only use non-optionals if you're sure that the variable will have a value else use optionals.
As I started developing with Swift and searching through different tutorials and documentations about the language, I'm not sure about one thing.
You can declare an object / value with a specific data type like this:
var aString:String = "Test"
var anObject:SKScene = ASceneClass()
Or you can just do it like this:
var aString = "Test"
var anObject = ASceneClass()
The result will be exactly the same (ASceneClass inherits from SKScene of course)
As everyone is doing it different I wonder if there's a logical reason behind it or you do it for readability ?
Declaring type right after variable name is called Type Annotation
When you don't do that, you have to provide initial value
var aString = "Test"
Often value is not known at that moment, or you are not even sure if it's going to be not nil value, then you can declare it as optional
var aString:String?
If you would like to declare variable without any initiaization but you are sure it's not going to evaluate to nil, you force unwrap it
var aString:String!
This is the definition. In practice, it's always better to use type annotations even when you initialize variable with value, because later in your program you will notice anytime you mess something with the type of the variable.
Also, When you declare an array or dictionary, usually nested ones, Xcode might expect them to have type annotations since it might have some issues with writing values when the type is not known in advance.
To recap
You will want to use type annotations whenever you can, which means whenever you are sure about the variable's type in advance
Recommended/Documented way to declare a variable in swift is as follow:
var <variable name>: <type> = <initial value/expression>
Note: Given form declares a stored variable or stored variable property. Its used when you are clear about type annotation of it.
Though its valid to declare variable without its Type.
var variableName = <initial value>
Note: When you don't know type annotation its mandatory to assign 'Initial value' to that variable.
Refer Swift Documentation on Declaration for more details.
I'm new to Swift and iOS coding and have been working on writing my first app. While my programming background is pretty significant, I come from a Python and C# background where pretty much anything can be None or null and it's up to the user to check at runtime for a null. I'm finding this whole concept of "nullable vs. non-nullable types" or "optional types" in Swift to be confusing.
I understand that the core concept is that a variable declared as a type like myObject cannot be set to nil. However, if I define it as type myObject? then the value can be set to nil.
The problem is that, when I look at my code designs, it feels like everything will have to be "nullable" in my code. It feels like this either means I'm not thinking correctly with how my code should run, or that I'm missing some crucial piece of understanding.
Let's take the simplest example of something I am confused about. Suppose I have two classes - one that stores and manages some sort of data, and another that provides access to that data. (An example of this might be something like a database connection, or a file handle, or something similar.) Let's call the class containing data myData and the class that works with that data myObject.
myObject will need a class-level reference to myData because many of its methods depend on a local reference to the class. So, the first thing the constructor does is to generate a data connection and then store it in the local variable dataConnection. The variable needs to be defined at the class level so other methods can access it, but it will be assigned to in the constructor. Failure to obtain the connection will result in some sort of exception that will interfere with the very creation of the class.
I know that Swift has two ways to define a variable: var and let, with let being analogous to some languages' const directive. Since the data connection will persist throughout the entire life of the class, let seems an obvious choice. However, I do not know how to define a class-level variable via let which will be assigned at runtime. Therefore, I use something like
var dataConnection: myData?
in the class outside any functions.
But now I have to deal with the nullable data type, and do explicit unwrapping every time I use it anywhere. It is frustrating to say the least and quite confusing.
func dealWithData() {
self.dataConnection.someFunctionToGetData() <- results in an unwrapping error.
self.dataConnection!.someFunctionToGetData() <- works.
let someOtherObjectUsingData: otherObject = self.getOtherObject() <- may result in error unless type includes ?
someOtherObjectUsingData.someMethod(self.dataConnection) <- unwrap error if type included ?
var myData = self.dataConnection!
someOtherObjectUsingData.someMethod(myData) <- works
}
func somethingNeedingDataObject(dataObject: myData?) {
// now have to explicitly unwrap
let myDataUnwrapped = myData!
...
}
This just seems to be an extremely verbose way to deal with the issue. If an object is nil, won't the explicit unwrap in and of itself cause a runtime error (which could be caught and handled)? This tends to be a nightmare when stringing things together. I've had to do something like:
self.dataConnection!.somethingReturningAnObject!.thatObjectsVariable!.someMethod()
var myData? = self.dataConnection
var anotherObject? = myData!.somethingReturningAnObject
...
The way I'm used to doing this is that you simply define a variable, and if it is set to null and you try to do something with it, an exception (that you can catch and handle) is thrown. Is this simply not the way things work anymore in Swift? This has confused me sufficiently that just about every time I try to compile an app, I get tons of errors about this (and I just let Xcode fix them). But this can't be the best way to deal with it.
Do I have to consistently deal with wrapping and unwrapping variables - even those which are expected to never be null in the first place but simply can't be assigned at compile time?
However, I do not know how to define a class-level variable via let which will be assigned at runtime.
This part is easy. Just use let instead of var. With Swift 1.2 and later, you can delay the actual assignment of a let. The compiler is smart enough to do flow analysis and make sure it's assigned once, and only once, in all paths. So in the case of a class-wide let, the assignment can also happen in the constructor.
But now I have to deal with the nullable data type, and do explicit unwrapping every time I use it anywhere.
But this is what implicitly unwrapped Optionals are for. For example, StoryBoard defines all #IBOutlets as implicitly unwrapped, because the semantics are very clear: upon entrance to viewDidLoad() and everywhere after, unwrapping is safe. If you can prove clear semantics to yourself, you can do the same.
So you have roughly 4 choices:
A) declare at class level as implicitly unwrapped:
let dataConnection: MyData!
And be forced to initialize it in the constructor:
init() {
let whateverObj = someInitialCalculation()
dataConnection = whateverObj.someWayOfGettingTheConnection()
}
And from then on you don't need the '!'; it should be clear that implicit unwrap is always safe.
B) Initialize it right in its declaration if its initialization is reliable and sensible at that point, allowing you to forgo the entire concept of Optionals:
let dataConnection = SomeClass.someStaticMethod()
C) Declare at class level as a var, as implicit optional:
var dataConnection: MyData!
You won't have to init it in the constructor; let it be nil until its value can/should be computed. You still need some flow analysis to prove after a certain point, as in the case of #IBOutlets, accessing it will always be valid
D) The most 'unpredictable' case. Declare it as an explicit optional, because throughout the lifecycle of the class, the data connection will come and go:
var dataConnection: MyData?
func someMethodThatHandlesData() {
if let dC = dataConnection {
dc.handleSomeData()
}
else {
alert("Sorry, no data connection at the moment. Try again later.")
}
}
I think you're imagining that Swift always forces you down path D).
As far as your spaghetti-string code, you want to look into Optional Chaining, and only need to check the end result for nil.
I'm really new to Swift and I just read that classes are passed by reference and arrays/strings etc. are copied.
Is the pass by reference the same way as in Objective-C or Java wherein you actually pass "a" reference or is it proper pass by reference?
Types of Things in Swift
The rule is:
Class instances are reference types (i.e. your reference to a class instance is effectively a pointer)
Functions are reference types
Everything else is a value type; "everything else" simply means instances of structs and instances of enums, because that's all there is in Swift. Arrays and strings are struct instances, for example. You can pass a reference to one of those things (as a function argument) by using inout and taking the address, as newacct has pointed out. But the type is itself a value type.
What Reference Types Mean For You
A reference type object is special in practice because:
Mere assignment or passing to function can yield multiple references to the same object
The object itself is mutable even if the reference to it is a constant (let, either explicit or implied).
A mutation to the object affects that object as seen by all references to it.
Those can be dangers, so keep an eye out. On the other hand, passing a reference type is clearly efficient because only a pointer is copied and passed, which is trivial.
What Value Types Mean For You
Clearly, passing a value type is "safer", and let means what it says: you can't mutate a struct instance or enum instance through a let reference. On the other hand, that safety is achieved by making a separate copy of the value, isn't it? Doesn't that make passing a value type potentially expensive?
Well, yes and no. It isn't as bad as you might think. As Nate Cook has said, passing a value type does not necessarily imply copying, because let (explicit or implied) guarantees immutability so there's no need to copy anything. And even passing into a var reference doesn't mean that things will be copied, only that they can be if necessary (because there's a mutation). The docs specifically advise you not to get your knickers in a twist.
Everything in Swift is passed by "copy" by default, so when you pass a value-type you get a copy of the value, and when you pass a reference type you get a copy of the reference, with all that that implies. (That is, the copy of the reference still points to the same instance as the original reference.)
I use scare quotes around the "copy" above because Swift does a lot of optimization; wherever possible, it doesn't copy until there's a mutation or the possibility of mutation. Since parameters are immutable by default, this means that most of the time no copy actually happens.
It is always pass-by-value when the parameter is not inout.
It is always pass-by-reference if the parameter is inout. However, this is somewhat complicated by the fact you need to explicitly use the & operator on the argument when passing to an inout parameter, so it may not fit the traditional definition of pass-by-reference, where you pass the variable directly.
Here is a small code sample for passing by reference.
Avoid doing this, unless you have a strong reason to.
func ComputeSomeValues(_ value1: inout String, _ value2: inout Int){
value1 = "my great computation 1";
value2 = 123456;
}
Call it like this
var val1: String = "";
var val2: Int = -1;
ComputeSomeValues(&val1, &val2);
The Apple Swift Developer blog has a post called Value and Reference Types that provides a clear and detailed discussion on this very topic.
To quote:
Types in Swift fall into one of two categories: first, “value types”,
where each instance keeps a unique copy of its data, usually defined
as a struct, enum, or tuple. The second, “reference types”, where
instances share a single copy of the data, and the type is usually
defined as a class.
The Swift blog post continues to explain the differences with examples and suggests when you would use one over the other.
When you use inout with an infix operator such as += then the &address symbol can be ignored. I guess the compiler assumes pass by reference?
extension Dictionary {
static func += (left: inout Dictionary, right: Dictionary) {
for (key, value) in right {
left[key] = value
}
}
}
origDictionary += newDictionaryToAdd
And nicely this dictionary 'add' only does one write to the original reference too, so great for locking!
Classes and structures
One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference.
Closures
If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles
ARC(Automatic Reference Counting)
Reference counting applies only to instances of classes. Structures and enumerations are value types, not reference types, and are not stored and passed by reference.
Classes are passed by references and others are passed by value in default.
You can pass by reference by using the inout keyword.
Swift assign, pass and return a value by reference for reference type and by copy for Value Type
[Value vs Reference type]
If compare with Java you can find matches:
Java Reference type(all objects)
Java primitive type(int, bool...) - Swift extends it using struct
struct is a value type so it's always passed as a value. let create struct
//STEP 1 CREATE PROPERTIES
struct Person{
var raw : String
var name: String
var age: Int
var profession: String
// STEP 2 CREATE FUNCTION
func personInformation(){
print("\(raw)")
print("name : \(name)")
print("age : \(age)")
print("profession : \(profession)")
}
}
//allow equal values
B = A then call the function
A.personInformation()
B.personInformation()
print(B.name)
it have the same result when we change the value of 'B' Only Changes Occured in B Because A Value of A is Copied, like
B.name = "Zainab"
a change occurs in B's name. it is Pass By Value
Pass By Reference
Classes Always Use Pass by reference in which only address of occupied memory is copied, when we change similarly as in struct change the value of B , Both A & B is changed because of reference is copied,.