Swift: How to define a UIView delegate with unowned(unsafe) reference? - swift

I find the following code in UITableView class,
unowned(unsafe) var delegate: UITableViewDelegate?
so I wander how to define a unowned(unsafe) reference delegate for UIView, then I encounter the following error when I write the unowned(unsafe) keyword in my class,
/Users/larryhou/Documents/Xcode/AtomicElements/AtomicElements/AtomicElementView.swift:32:25: 'unowned' cannot be applied to non-class type 'AtomicElementViewDelegate?'
protocol AtomicElementViewDelegate:NSObjectProtocol
{
func didTap(target:AtomicElementView, sender:UITapGestureRecognizer)
}
I can only use weak keyword, but I want keep the reference until UIView is deallocated.

Those two designations - unowned and weak - are equivalent from the perspective of references. Where they differ is the presumption of existence - in Swift, unowned instances are presumed to always exist as long as reference to them does, whereas weak instances are optionals - they may exist, or they may not, so you need to use optional chaining or some other means of working with them.
In UIKit, the delegate pattern with UIView subclasses is to declare them as weak because the delegate is nearly always the view controller that owns the view that the subclass is a subview of. Declaring a delegate as strongly referenced in that situation would set up a reference cycle, hence delegates are typically declared with the weak keyword. If you have a different situation, you can allow your delegate to be strongly referenced by simply leaving out the weak keyword.
In this particular case, unowned (unsafe) is an artifact of being bridged from ObjC.

how to define a unowned(unsafe) reference delegate for UIView
You can't. And you shouldn't want to. unowned(unsafe) is a way of expressing the Objective-C non-ARC assign policy, i.e. no memory management. It is horrible and dangerous (and can cause crashes). The name tells you what the problem is. It is unsafe!!! There is no Swift equivalent because Swift has built-in memory management. This is one of the reasons why Swift is good. Don't worry be happy.
But do be careful, because this designation is warning you that if the delegate goes out of existence while the UITableView still exists, you will crash because the table view will not know this and may try to send a message to the non-existent delegate.

Related

Swift, two issues. 1) weak var 2) bang operator for #IBOutlet

Per:
#IBOutlet weak var nameLabel: UILabel!
Whenever I declare my IBOutlets, i just use var instead of weak var. But I've recently come across a few code templates that use weak var. Why do they do it? What's the added benefit?
Why is there a bang operator at the end of UILabel. I know it's required and i go along w/ it, but just asking it now.
Thanks in advance.
Swift IBOutlet are weak by default (but others properties are strong by default). So both writing are the same.
You have more details about the difference between weak and strong here
According to apple documentation
When you declare an outlet in Swift, you should make the type of the
outlet an implicitly unwrapped optional (!). This way, you can let the
storyboard connect the outlets at runtime, after initialization.
The outlets are weak since the view elements are owned (strongly) by the view. I think it's technically OK for your view controller to have a strong reference too, but not necessary.
Weak variables are optional since they can be nil. You can declare your outlets with ? instead but that means using force-unwrapping or optional binding every time. Declaring them as implicitly-unwrapped optionals with ! is just a convenience.
You use weak when referring to IBOutlets because so long as the object remains in its superview there will be a strong reference to it. See weak or strong for IBOutlets.
Next, the bang operator indicates that the IBOutlet is an explicitly unwrapped label. With the bang operator, it guarantees that the object will exist, so when referencing it, you can simply reference it like this:
someLabel.text = "some text"
However, you can make them IBOutlets optional:
#IBOutlet weak var someLabel: UILabel?
But you must use ? when accessing them
someLabel?.text = "some text"
#gregheo's response is the best explained, to further elaborate: if you consider ownership in this situation the View object referred to by the #IBOutlet usually shouldn't be owned by the View Controller referring to it.
Rather it should be owned by its superview wherever it may be in the tree (which happens strongly by UIView.subviews). The View Controller instead owns the very root of it's View Tree strongly (UIViewController.view). weak explicitly declares a non-owning reference that may become nil at different points in the View Controller's life.
Here I would offer an alternative to using !: using an implicitly unwrapped optional reference is a dangerous practice that weakens the tools Swift offers us. A View Controller which is loaded from Xib or Storyboard includes in its lifetime a regular time after being created and before it's View has been loaded where the #IBOutlet reference is nil, every time. To assume no one will operate on the member during that time means not using the Swift grammar and compiler's feedback to our advantage.
Additionally #IBOutlets are a powerful tool that enables a flexible, visually focused approach when designing a screen or view. It is common practice to have your View Controller expose #IBOutlets for all information it has available, regardless of whether or not it is known that it will be used and separately deciding which to actually connect and use when building and iterating on the View from within Interface Builder.
Additionally-additionally if your View should be flexible enough to be instantiated from Xib/Storyboard AND from code, depending on how you decide referenced subviews should be instantiated and connected they may or may not be available immediately.
For the reasons above I define mine: #IBOutlet weak var nameLabel: UILabel?

How does Swift memory management work?

Specifically, how does Swift memory management work with optionals using the delegate pattern?
Being accustomed to writing the delegate pattern in Objective-C, my instinct is to make the delegate weak. For example, in Objective-C:
#property (weak) id<FooDelegate> delegate;
However, doing this in Swift isn't so straight-forward.
If we have just a normal looking protocol:
protocol FooDelegate {
func doStuff()
}
We cannot declare variables of this type as weak:
weak var delegate: FooDelegate?
Produces the error:
'weak' cannot be applied to non-class type 'FooDelegate'
So we either don't use the keyword weak, which allows us to use structs and enums as delegates, or we change our protocol to the following:
protocol FooDelegate: class {
func doStuff()
}
Which allows us to use weak, but does not allow us to use structs or enums.
If I don't make my protocol a class protocol, and therefore do not use weak for my variable, I'm creating a retain cycle, correct?
Is there any imaginable reason why any protocol intended to be used as a delegate protocol shouldn't be a class protocol so that variables of this type can be weak?
I primarily ask, because in the delegation section of the Apple official documentation on Swift protocols, they provide an example of a non-class protocol and a non-weak variable used as the delegate to their class:
protocol DiceGameDelegate {
func gameDidStart(game: DiceGame)
func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
func gameDidEnd(game: DiceGame)
}
class SnakesAndLadders: DiceGame {
let finalSquare = 25
let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())
var square = 0
var board: [Int]
init() {
board = [Int](count: finalSquare + 1, repeatedValue: 0)
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
}
var delegate: DiceGameDelegate?
func play() {
square = 0
delegate?.gameDidStart(self)
gameLoop: while square != finalSquare {
let diceRoll = dice.roll()
delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
switch square + diceRoll {
case finalSquare:
break gameLoop
case let newSquare where newSquare > finalSquare:
continue gameLoop
default:
square += diceRoll
square += board[square]
}
}
delegate?.gameDidEnd(self)
}
}
Should we take this as a hint that Apple thinks we should be using structs as delegates? Or is this simply a bad example, and realistically, delegate protocols should be declared as class-only protocols so that the delegated object can hold a weak reference to its delegate?
Should we take this as a hint that Apple thinks we should be using structs as delegates? Or is this simply a bad example, and realistically, delegate protocols should be declared as class-only protocols so that the delegated object can hold a weak reference to its delegate?
Here's the thing. In real life Cocoa programming, the delegate is likely to be an existing class. It is a class because it exists for some other purpose that only a class can satisfy - because Cocoa demands it.
For example, very often, to take iOS as an example, one view controller needs to act as another view controller's delegate for purposes of arranging a message back and forth between them. Ownership of the view controllers is dictated by the view controller hierarchy and by nothing else. So, in Swift, just as in Objective-C, you had better make that delegate property weak, because it would be terrible if one view controller suddenly took memory management ownership of another view controller!
So, in the real world of the Cocoa framework, there is serious danger of incorrect ownership or of a retain cycle. And that is the problem that weak solves. But it only works, as you rightly say, with classes.
The example in the book, however, is about some objects living off in an abstract made-up artificial Swift-only world. In that world, as long as you aren't in danger of circularity (retain cycle), there's no reason not to use structs and there's no reason to worry about memory management. But that world is not the world you will usually be programming in! And that world is not the framework Cocoa world that your Objective-C delegate pattern comes from and belongs to.
Yes, this example is a bit of an oddity.
Because the example uses a non-class protocol type, it has to expect a possible struct implementing the protocol, which means that the DiceGame instance owns its delegate. And indeed, that violates typical assumptions about the delegate pattern.
It doesn't lead to a reference cycle in this case because the DiceGameTracker is a fictional object that doesn't own the DiceGame itself — but in a real-world app it's possible, even likely, that a delegate might also be the owner of the delegating object. (For example, a view controller might own the DiceGame, and implement DiceGameDelegate so it can update its UI in response to game events.)
That kind of reference cycle would probably turn into a confusing mess if either the game, its delegate, or the type implementing one or both of those protocols were a value type — because value types are copied, some of the variables in your setup would end up being distinct copies of the game (or game's owner).
Realistically one would expect to use reference types (classes) to implement this anyway, even if the protocol declaration leaves open the possibility of doing it otherwise. Even in a hypothetical Swift-only world, it probably makes sense to do it that way... generally whenever you have something with long life, internal mutable state, and a usage pattern that has it being accessed by potentially multiple other actors, you want a class type, even if you can sort of fake otherwise with value types and var.
If you must have structs and emums in your protocol, then if you make your delegate nil just before you close the view controller, then this breaks the retain cycle. I verified this in Allocations in Instruments.
// view controller about to close
objectCreatedByMe.delegate = nil
It's an optional, so this is valid.

Type and declaration restrictions on Swift capture specifiers

I'm confused about the type requirements and declaration restrictions for Swift capture specifiers. The documentation says that weak references must be var and "of optional type", and that unowned references must be of non-optional type. But Apple's own API reference has examples of unowned(unsafe) references declared as optionals, while the Xcode interface builder creates weak outlets and actions that are implicitly unwrapped (which is not always clearly "of optional type" in the language reference).
What types are required for each of the Swift capture specifiers? Which must be var and which can be let?
FWIW, I think its
weak can be Type? or Type!, but not Type; and must be var
unowned(safe) (same as unowned) must be Type; and may be let
unowned(unsafe) can be Type? or Type!; and may be let
but I'm far from sure.
First the Cocoaor Cocoa touch APIs are imported in swift fromobjective-c`. They are mapped in swift with best possible ways.So that both can interoperable.
Those unowned(unsafe) properties are marked as assign in ObjC. These are unsafe and ARC doesn't retain the object, and it doesn't make sure the reference gets reset to nil if the object is deallocated. These are old apple API and not changed with ARC and remain asassignbut you should makedelegateweak`
Do not look for headers for best practices in swift they have made many tricks to make swift and objective-c interoperable and if you do what headers do than you loose all safety swift proveide.
You are right
weak should be optional as contain nil automatically if objects get deallocate and no other pointer retain it
unowned(safe) should not be optional and will not reset to nilif objects deal-located
unowned(unsafe) can or can not be optional as it not provide any safety by ARC for object deal-location and do not reset to nil.You should not use this in swift program.Use unowned if needed.It is just for interoperability.
weak is always var because it can be changed when objects deallocate and set to nil.
unowned(safe) and unowned(unsafe) can be both var or let as they are dependent on you and run-time will not change these variables.
Note:You can not declare a unowned(unsafe) as optional in swift program.Its for just interoperability and should not be used in swift.They have made this because of assign or unretain properties can be nil

How can I make a weak protocol reference in 'pure' Swift (without #objc)

weak references don't seem to work in Swift unless a protocol is declared as #objc, which I don't want in a pure Swift app.
This code gives a compile error (weak cannot be applied to non-class type MyClassDelegate):
class MyClass {
weak var delegate: MyClassDelegate?
}
protocol MyClassDelegate {
}
I need to prefix the protocol with #objc, then it works.
Question: What is the 'pure' Swift way to accomplish a weak delegate?
You need to declare the type of the protocol as AnyObject.
protocol ProtocolNameDelegate: AnyObject {
// Protocol stuff goes here
}
class SomeClass {
weak var delegate: ProtocolNameDelegate?
}
Using AnyObject you say that only classes can conform to this protocol, whereas structs or enums can't.
Supplemental Answer
I was always confused about whether delegates should be weak or not. Recently I've learned more about delegates and when to use weak references, so let me add some supplemental points here for the sake of future viewers.
The purpose of using the weak keyword is to avoid strong reference cycles (retain cycles). Strong reference cycles happen when two class instances have strong references to each other. Their reference counts never go to zero so they never get deallocated.
You only need to use weak if the delegate is a class. Swift structs and enums are value types (their values are copied when a new instance is made), not reference types, so they don't make strong reference cycles.
weak references are always optional (otherwise you would used unowned) and always use var (not let) so that the optional can be set to nil when it is deallocated.
A parent class should naturally have a strong reference to its child classes and thus not use the weak keyword. When a child wants a reference to its parent, though, it should make it a weak reference by using the weak keyword.
weak should be used when you want a reference to a class that you don't own, not just for a child referencing its parent. When two non-hierarchical classes need to reference each other, choose one to be weak. The one you choose depends on the situation. See the answers to this question for more on this.
As a general rule, delegates should be marked as weak because most delegates are referencing classes that they do not own. This is definitely true when a child is using a delegate to communicate with a parent. Using a weak reference for the delegate is what the documentation recommends. (But see this, too.)
Protocols can be used for both reference types (classes) and value types (structs, enums). So in the likely case that you need to make a delegate weak, you have to make it an object-only protocol. The way to do that is to add AnyObject to the protocol's inheritance list. (In the past you did this using the class keyword, but AnyObject is preferred now.)
protocol MyClassDelegate: AnyObject {
// ...
}
class SomeClass {
weak var delegate: MyClassDelegate?
}
Further Study
Reading the following articles is what helped me to understand this much better. They also discuss related issues like the unowned keyword and the strong reference cycles that happen with closures.
Delegate documentation
Swift documentation: Automatic Reference Counting
"Weak, Strong, Unowned, Oh My!" - A Guide to References in Swift
Strong, Weak, and Unowned – Sorting out ARC and Swift
Related
How to make delegates in Swift
iOS: How To Make Weak Delegates In Swift
Swift delegation - when to use weak pointer on delegate
AnyObject is the official way to use a weak reference in Swift.
class MyClass {
weak var delegate: MyClassDelegate?
}
protocol MyClassDelegate: AnyObject {
}
From Apple:
To prevent strong reference cycles, delegates should be declared as
weak references. For more information about weak references, see
Strong Reference Cycles Between Class Instances. Marking the protocol
as class-only will later allow you to declare that the delegate must
use a weak reference. You mark a protocol as being class-only by
inheriting from AnyObject, as discussed in Class-Only Protocols.
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID276
Update:
It looks like the manual has been updated and the example I was referring to has been removed. See the edit to #flainez's answer above.
Original:
Using #objc is the right way to do it even if you're not interoperating with Obj-C. It ensures that your protocol is being applied to a class and not an enum or struct. See "Checking for Protocol Conformance" in the manual.
The weak qualifier only applies to reference objects. Unless you add the #objc, AnyObject, or class qualifier on your protocol, the object conforming to the protocol might not be a reference object.
Thus you need on of those qualifiers (and AnyObject is recommended, since class is expected to be deprecated.)
By the way, note that adding #objc to your classes and properties is sometimes required, even in "pure Swift" applications. It doesn't have to do with you development language. It causes the compiler to build your code in a way that is compatible with the Objective-C runtime, which is required for some OS interfaces (target/action and old-style key paths for example)
protocol MyProtocol {
func doSomething()
}
class MyClass: MyProtocol {
func doSomething() {
print("Doing something")
}
}
var weakProtocol: Weak<MyProtocol>?
let myObject = MyClass()
weakProtocol = Weak(myObject)
weakProtocol?.doSomething() // Will print "Doing something"
protocol must be subClass of AnyObject, class
example given below
protocol NameOfProtocol: class {
// member of protocol
}
class ClassName: UIViewController {
weak var delegate: NameOfProtocol?
}
Apple uses "NSObjectProtocol" instead of "class".
public protocol UIScrollViewDelegate : NSObjectProtocol {
...
}
This also works for me and removed the errors I was seeing when trying to implement my own delegate pattern.

Calling method using optional chaining on weak variable causes EXC_BAD_ACCESS

Update: This is fixed in Xcode 6 beta 6.
The following code causes an EXC_BAD_ACCESS on the delegate?.thing() line:
#class_protocol protocol Fooable {
func foo()
}
class Bar : Fooable {
func foo() {
}
}
weak var delegate: Fooable?
let bar = Bar()
delegate = bar
delegate?.foo()
But everything seems right to me. In order for a variable to be weak, it must have optional type. So the variable delegate is optional. A weak variable's type must also be a class type, so I made the protocol a class protocol. Since I use optional chaining, I expect it to either 1) be nil, and do nothing, or 2) not be nil, and call the method, which should succeed. However, it crashes.
Could it be that optional chaining is not atomic and doesn't retain the expression and the object somehow gets deallocated in between the check for nil and the subsequent call?
Interestingly, if you eliminate the variable bar and assign it directly as delegate = Bar(), the crash goes away. This is really perplexing because assigning an expression to a variable and then assigning the variable and assigning the expression directly should generally behave the same.
I suspect the reason weak var delegate: Fooable?is not working is because that line of code, which is using optional chaining, is checking for protocol conformance.
According to Apple Swift Programming manual:
“Even if you are not interoperating with Objective-C, you need to mark
your protocols with the #objc attribute if you want to be able to
check for protocol conformance.”
If you substitute #class_protocol with #objc it should not crash. Also as per the manual, using #objc only allows the protocol to be adopted by classes (no structs or enums conformance).
Like #PartiallyFinite, I had to play with the code a little too. Apple's iBook on Swift has a blurb about this that may help (with a protocol named ExampleProtocol and a class SimpleClass that conforms to that protocol):
"Even though the variable protocolValue has a runtime type of SimpleClass, the compiler treats it as the given type of ExampleProtocol. This means that you can’t accidentally access methods or properties that the class implements in addition to its protocol conformance.”
That said, you should be able to call foo() on your delegate (barring it doesn't go away before calling it), but just remember the delegate here is declared to be of type Fooable?, not Bar, under the hood. This may be a bug, but I got it to work by entering:
weak var delegate: Bar? = bar
delegate?.foo()