Is backed property safer than (lazy) in Swift? - swift

Is it safer to use computed property backed by another property, than to use lazy modifier in Swift?
// method 1: using LAZY variable
lazy var myVar:Int {
// assume that this calculation takes
// a lot of time and resources
return 5
}
Now consider the following quote from Apple's Swift 2 (Pre-release):
NOTE
If a property marked with the lazy modifier is accessed by multiple
threads simultaneously and the property has not yet been initialized,
there is no guarantee that the property will be initialized only once.
Personally, I have been doing my own "lazy" logic like this:
Consider the alternative approach:
// method 2: using calculated property backed by another property
var myVar:Int? {
if self._myVar != nil {
return self._myVar
}
let aVar:Int = 5 // assume this is done after exhaustive calcuation
self._myVar = aVar
return self._myVar
}
var _myVar:Int? = nil
Using (method 2), do I get guarantee that the "exhaustive calculation" will only be executed once?

Your proposed method 2 does not guarantee anything that lazy does not.
// method 2: using calculated property backed by another property
var myVar:Int? {
if self._myVar != nil {
return self._myVar
}
let aVar:Int = 5 // assume this is done after exhaustive calcuation
self._myVar = aVar
return self._myVar
}
var _myVar:Int? = nil
Moreover, it has the added pitfall of being an optional rather than a non-optional. This would be slightly better as an implicitly unwrapped optional so we don't have to continuously unwrap it.
And, we can't set myVar. Plus _myVar should be private.
But the problem is that you're not locking the initialization code down to be synchronized.
Suppose you have thread A start to access myVar. The if self._myVar != nil check returns false, so we're not returning self._myVar. Now we enter the exhaustive calculation.
Now before exhaustive calculation completes, Thread B tries accessing myVar. Because Thread A has not completed exhaustive calculation yet, the if self._myVar != nil still returns false, and now Thread B does the exhaustive calculation.
Essentially, this is this the same problem that the lazy keyword gives you.... but you wrote a whole lot of code to do it that way when lazy would have sufficed.

Related

How can I deallocate all references elements from an array?

I'm trying to create a retrying mechanism for our network calls. I have created 2 classes. One a retry Class and another a Manager in case I wanted I can cancel all classes.
class Retry {
var url: String
var maxRetries: Int
init (url: String, retryCount: Int){
self.url = url
self.maxRetries = maxRetries
poll()
RetryManager.shared.add(self)
}
private func poll(){
guard retryCount == 0 else{
print("error")
}
getRequest()
}
private func getRequest(){
// make network request
// if no response is received poll again
}
func cancel(){
maxRetries = 0
}
}
Manager class
class RetryManager{
static let sharedInstance = RetryManager()
var retries : [Retry?] = []
private init(){
}
func register(retry: Retry){
retries.append(retry)
}
func remove(retry: Retry){
retry.cancel() // XX; Do I also need this or just removing it is fine?
retries = retries.filter({$0 !== retry})
}
func cancelAll(){
retries.forEach({$0?.cancel()}) // ZZ; Do I also need this? or just removing them is fine?
retries.removeAll()
}
}
My Retry instances are to be used for making network calls.
My major question is about my cancel mechanism. Will doing a RetryManager.shared.cancelAll() suffice for deallocation? Or I need to run cancel or each cancel instance (ie XX, ZZ are also necessary)?
Currently everything works fine, but I'm not sure if I how it would work if I have multiple pointers...would I need to do:
for index..<retries.count{
retries[index] = nil
}
As far as I understand that won't help, it's same as doing retries.removeAll()
I also read In Swift, how do I set every element inside an array to nil? question but was told to open a new question
Not sure if I can answer your question, but I will try with my best understanding :).
Apple's Swift handbook on Automatic Reference Counting (ARC) covers your question very well.
Usually you don't need to have an array of optionals,
var retries = [Retry]()
...
retries.removeAll()
will nicely remove all containing objects and delete the references to these objects. From your context presented above I do not understand why you need to declare an array of optionals. As you know Swift optionals under the hood are just a typed wrapper class Optional<Type>, which doesn't work around the memory allocation problem.
How does array reference objects?
The array will increase the contained objects' reference count by one, that is, a strong reference.
To ensure the objects in the array to be deallocated, one must make their reference count equal zero. Removing them from the array will do the trick, if nothing else is referencing the contained objects.
Beware of the reference cycle though. In your case, you should not hold reference to the retries array in Retry instance. Otherwise even if you set the retries array to nil, the array and its contained objects still have strong reference to each other, meaning their reference counts will never reduce to zero, causing memory leak.

Can't set nil to an optional property with custom setter in Swift

I have swift class with various properties, some of which have optional types.
class UserObject: PFUser{
//optional property
var optionalPhotoURL:String? {
get {
if let optionalPhotoURL:String = objectForKey("optionalPhotoURL"){
return optionalPhotoURL
}
//not needed but just for emphasis
return nil
}
//I am unable to set UserObject.optionalPhotoURL = nil with this setters
set {
if let newPhotoURL:String = newValue! {
setObject(newPhotoURL, forKey: "optionalPhotoURL")
}else{
self.optionalPhotoURL = nil
}
}
}
}
I am unable to set optionalPhotoURL as nil, if it already had a previous value assigned to it.
I guess my question is, how do i "unset" an optional property with custom setter?
Update
These setters all crash
set {
if let newPhotoURL:String = newValue {
setObject(newPhotoURL, forKey: "optionalPhotoURL")
}else{
self.optionalPhotoURL = nil
}
}
and this
set {
if (newValue != nil) {
setObject(newValue!, forKey: "optionalPhotoURL")
}else{
self.optionalPhotoURL = nil
}
}
What you have here is a computed property.
Swift properties can either be computed or stored. We can observe value changes in our stored properties by using didSet and willSet but here we still have a stored property.
In your case, since you have overridden set and get*, you don't have a stored property, you have a computed property. If you want a computed property to have a backing storage, you must create that independently.
So you may want something like this:
class FooClass {
private var storageProperty: String?
var accessProperty: String? {
get {
return self.storageProperty
}
set {
self.storageProperty = newValue
// or whatever logic you may like here
}
}
}
*: You can't override set without also overriding get. You can however override get without overriding set--this makes a readonly computed value.
Moreover, it's important that we implement our storage properties in this way over relying on key-value coding.
For starters, setObject(forKey:) approach doesn't even work on pure Swift types. This will only work on objects which inherit from Objective-C types. It's an inherited method from NSObject's compliance to NSKeyValueCoding protocol. Why the base object of Objective-C conforms to so many protocols is beyond me... but it does and there's nothing we can do about it.
If we have a code base in which some of our objects are inheriting from Objective-C objects (which basically any project will have, UIViewController, etc), and some of our objects are pure Swift objects (which you will tend to have when you're creating your own Swift classes from scratch), then our Swift objects will not be able to implement this same pattern. If we have some objects of both types, we'll either have to implement the pattern I show above for all of them (and then we have consistency) or we'll have to implement one pattern for some types and another for other types (Swift structs would definitely have to implement the above pattern, you can't just make them inherit from NSObject) (and then we have inconsistency, which we don't like).
But what's far worse about setObject(forKey:) is that the first argument of this method always will be of type AnyObject. There is no type safety to the method at all. Where things are stored via setObject(forKey:) is based purely on the key which we use. When we use setObject(forKey:), we take a pile of type-safety advantages that Swift gives us and we throw them out the window. If we don't care to leverage the advantages Swift gives us over Objective-C, why are we writing it in Swift at all?
We can't even make the stored property private when we use setObject(forKey:). Anyone who knows the key can call setObject(forKey:) and set that object to whatever they want. And that includes objects which are not strings. All we have to do to introduce a crash to this codebase is write a class extension or subclass which has a key collision on a different type other than what you've used (so maybe an NSData value for the same key). And even if it doesn't happen to be a different type, simply duplicating the same key for multiple properties is going to introduce bugs... and bugs that are hard to debug.
Never set a value of a computed property in its set scope by calling itself !
This causes an infinite loop and the app will crash.
I don't know which API setObject:forKey belongs to, but in the case of nil you are supposed to remove the object
set {
if let newPhotoURL = newValue {
setObject(newPhotoURL, forKey: "optionalPhotoURL")
} else {
removeObjectForKey("optionalPhotoURL")
}
}
Your property optionalPhotoURL is a computed property, it does not store any values:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
You might want to create an additional property which actually stores the value. However, why do you want to set it to nil, since you are not deleting they object in case of nil.

Is Swift optional chaining always done with the if let construction, or is it just done using a question mark with an optional?

As per Apple docs, optional chaining is the following:
You specify optional chaining by placing a question mark (?) after the optional value on which you wish to call a property, method or subscript if the optional is non-nil. ... optional chaining fails gracefully when the optional is nil ...
My interpretation of this is that a construction as the following is optional chaining:
someMasterObject.possiblyNilHandler?.handleTheSituation()
...and that the above line would call the handleTheSituation method if the handler is not nil, and fails gracefully (line skipped) if the handler is nil.
However almost all examples I see of optional chaining use the "if let" construction, as per:
if let handler = someMasterObject.possiblyNilHandler{
handler.handleTheSituation()
}
In fact, the documentation and examples I have found on the net make such heavy use of the "if let" construction in relation to optional chaining that it seems as if that IS optional chaining.
Am I correct, however, in assuming that my first example is a supported use of optional chaining and that the if let construction is another construction using (or being intimately tied to) optional chaining?
Optional chaining is useful in more cases than just optional binding (if let):
person?.name = "Fred" // assign "Fred" to name property if person is not nil
person?.congratulate() // call congratulate method if person is not nil
let name = person?.name ?? "none" // nil coalescing operator
let age = dict?["age"] ?? 0 // subscripting an optional variable
if var name = person?.name { // optional binding using var instead of let
The conclusion is correct - let is an independent, but useful, construct. In context it introduces a binding only within the if-body and executes the if-body only if the bound value is not-nil. (Technically it unwraps an optional binding.)
let does not affect how the expression on the right (with or without chaining) is handled. For instance, if someMasterObject were optional/nil it would fail and not "chain" - even with let.
When one or the other (or both) is more "correct" depends on the situation: eg. what is being chained and what the corrective action should be.
For instance, if someMasterObject could be nil, we might have the following which uses both chaining and let. Also note how the return value matters and is not simply discarded or "nil on failure":
if let handler = someMasterObject?.possiblyNilHandler{
return handler.handleTheSituation()
} else {
return FAILED_TO_CALL
}
Then compare it with a non-equivalent chained form, which would only return nil in the failed-to-call case, but nil might be a valid return value from handleTheSituation!
return someMasterObject?.possiblyNilHandler?.handleTheSituation()
On the other hand, do consider that there is always direct translation of chaining to nested if-let statements:
result_of_expression = someMasterObject?.possiblyNilHandle?.handleTheSituation()
if let master = someMasterObject {
if let handler = master.possiblyNilHandler {
result_of_expression = handler.handleTheSituation()
} else {
result_of_expression = nil
}
} else {
result_of_expression = nil
}
Calling methods through optional chaining is perfectly alright - you do not need an if around it. If the optional value happens to be nil at the time of the call, your code would not throw an exception. However, you wouldn't be able to find out whether the method has run or not.
However, typically you want to place an if around the optional chaining method call to detect if the method has been called or not:
func printNumberOfRooms() {
println("The number of rooms is \(numberOfRooms)")
}
if john.residence?.printNumberOfRooms() != nil {
println("It was possible to print the number of rooms.")
} else {
println("It was not possible to print the number of rooms.")
}
Link to the book chapter.
Note that the nil check works even though the function in the example has no return value. Since it is called on an optional value using optional chaining, the type is Void?, not Void, which makes the comparison possible.

Debugger displaying "some" instead of memory address

I have a method that creates an object an returns it as usual.
func myFunction() -> MyObject?{
var object = MyObject()
debugging it I can see that at the end of this function this object has a valid memory address.
return object
}
However when I receive it instead of displaying nil or the object address I can see the word "some". If I compare this object with nil it is not evaluated as a non nil object.
result = something.myFunction()
if result != nil {
println("never reaches here")
}
what is going on?
You've declared that method to return an optional MyObject. In Swift, optionals are implemented as an enum that has two possible values: .None, which is usually seen in its literal form, nil, and .Some, which holds the value of the optional as an associated value. You're seeing Some in the debugger because your method successfully returns a value wrapped in an optional.
You can read more about Optionals in the Swift language guide.

Reason for assigning optional to new variable in conditional statement in Swift

I'm going through the swift docs, and in the optional segment, it talks about using the question mark -- ? -- to signify variables that might be nil. This can be used in an if statement to check for nil, but in the docs they assign the optional to a new variable in the conditional. Is there a reason for this?
For Example, it is presented in the docs similar to this:
// Declare an optional string (might be nil)
var optionalString: String? = "Hello"
// Assigns optionalString to new variable before checking if nil
if let string = optionalString {
println("\(optionalString) is not nil!")
}
else {
println("\(optionalString) is nil")
}
However, this runs just fine for me in tests:
var optionalString: String? = "Hello"
// Assigns optionalString to new variable before checking if nil
if optionalString {
println("\(optionalString) is not nil!")
}
else {
println("\(optionalString) is nil")
}
Question
Is there a reason to assign optionalString to a new variable string in the conditional statement?
Take a look at the section on Optional Chaining in the docs. In the example you cite, there's not much difference. But in other cases, an if-let construction lets you get at an unwrapped value that comes from a series of optional references and method calls, without using implicit unwraps that can crash your app if you haven't considered all the possible bindings for a value in a chain.
It's also useful if you want to avoid recomputing a value. You can use it in a lot of the same ways you'd use an assignment in a conditional in (Obj)C (remember if (self = [super init])).
For example, if the optional being tested comes from a computed property:
var optionalName: String? {
get {
if checkTouchID() {
return "John Appleseed"
} else {
return nil
}
}
}
var greeting = "Hello!"
if optionalName != nil {
greeting = "Hello, \(optionalName)"
}
Paste that into a playground, along with a stub implementation of checkTouchID() that returns true, and you'll immediately see in the results area that the optionalName getter is executing twice. (This would be a problem in a more realistic scenario, because you probably don't want code like this to implicitly checkTouchID() or downloadFromServer() or billApplePay() twice.) If you use an if-let construction instead, you'll only execute the getter once.
In a series of chained optionals (like if let johnsStreet = john.residence?.address?.street in the docs linked above), you don't want to rewrite the whole chain in the body of the if statement, much less recompute it.
I think the purpose of that assignment was to demonstrate the use of "let" within the if conditional clause. I don't see a meaningful difference between the provided code and your own.
From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/il/jEUH0.l
“If the optional value is nil, the conditional is false and the code in braces is skipped. Otherwise, the optional value is unwrapped and assigned to the constant after let, which makes the unwrapped value available inside the block of code.”