> On 13 Jul 2017, at 19:43, Quincey Morris 
> <quinceymor...@rivergatesoftware.com> wrote:
> 
> Here’s how I understand the situation in Swift. As usual, I may have some 
> things a bit wrong, but I think this is right. There are four kinds of 
> reference variable (or stored property) in Swift:
> 
> 1. Strong.
> 
> 2. Weak.
> 
> 3. Unowned(safe), usually abbreviated to just “unowned”.
> 
> 4. Unowned(unsafe).
> 
> Note that these are attributes of the variable (i.e. storage location), not 
> the reference (i.e. pointer). It’s easy to forget that and talk about “strong 
> references” for example, but technically there’s no such thing.

Thanks Quincey - this is a really helpful discussion!

> “Unowned” means that the reference is non-optional and can persist after the 
> referenced object is deallocated. This avoids the performance penalty of 
> “weak”, but can’t provide a validity guarantee for the pointer — it’s up to 
> you to keep the object alive for as long as you use the unowned variable’s 
> reference. The clever part, which is specific to Swift, is that objects 
> secretly have *another* retain count, which is the number of *unowned* 
> variable references to the object. An object is not actually deallocated 
> until *both* retain counts go to zero — at which point there are obviously no 
> references to it any more. If you try to use an unowned variable reference 
> while the *main* reference count is zero and the *unowned* reference count is 
> non-zero, you are trying to use a zombie object and your app will immediately 
> crash.
> 
> Think about this. In effect, all Swift apps have zombie checking on all the 
> time. It’s impossible to use a reference to a non-alive object, and it’s 
> impossible for a stale pointer to refer to an instance of a different class 
> (which can happen in Obj-C if memory is re-allocated for another object while 
> you still hold a pointer to it.) It’s a simple but brilliant idea. It’s 
> pretty cheap, and it crashes as early as possible, which makes debugging 
> easier. What Dave meant, in the things you quoted, is that there’s an 
> overhead to this.  Aside from questions of optimization, the overhead is 
> similar to “strong” retain counting.

The secret retain count of unowned objects definitely helps to explain Dave’s 
comment, which was otherwise confusing. Without knowing this, it’s easy to get 
tied up in knots, as I was doing - if unowned objects have a retain count, how 
are they different from strong objects, and if they don’t have a retain count, 
how are they different from unowned(unsafe) objects? Your answer, which I 
haven’t seen elsewhere but was starting to suspect, is that they have a second 
retain count.

> “Unowned(unsafe)” means the same thing as “unretained unsafe” in Obj-C. It’s 
> just a pointer, and you’re responsible for knowing it’s safe to use at any 
> given time. Obviously, you’d like never to see one of these in Swift code.

Except for performance reasons, as you later say. Thinking about this, one 
might argue that safe unowned objects could be replaced by unowned(unsafe) 
objects in release code - in the same way that asserts are compiled out (and 
zombies are turned off) in release code. On the other hand, it’s easier for 
users to send bug reports if their crashes are repeatable. [I haven’t 
investigated, but maybe safe unowned objects are actually replaced by unsafe 
unowned objects with some optimisation settings?]

> The usage rules for these things are pretty straightforward to state, even 
> though it might be harder in particular cases to be sure what to use.
> 
> For owning variables, use strong. By default, use weak the rest of the time. 
> If you can reason that a non-owning variable is going to contain a valid 
> reference once initially set (like a “parent” reference in a child object to 
> which the parent has an owning reference in its “children” array, or like an 
> IBOutlet reference, usually), you can avoid the overhead of “weak” and use 
> “unowned” instead. (IIRC, you *must* declare a weak variable as optional, you 
> *must not* declare an unowned variable as optional, but you can declare 
> *either* as implicitly unwrapped optional.)

I don’t think an unowned variable can be any kind of optional, implicitly 
unwrapped or not. You might have been thinking of a discussion in the Swift 
book which deals with the question of how to have circular references (class A 
refers to B and class B refers to A) where both properties should have a value 
and neither should be nil. You can’t use unowned for both because init rules 
will prevent you from passing self to the other initialiser before you have 
finished initialising the first object. The book suggests that you could around 
this by using an implicitly unwrapped optional in one of the objects (this 
seems a bit kludgy to me). [See “Unowned References and Implicitly Unwrapped 
Optional Properties” in the ARC chapter.]

I was going to say I think the implicitly unwrapped optional in the Swift book 
example is a weak value, as suggested by the following code:

class Element
{
        let name = "fred"
}

var element = Element()

var elementReference1: Element! = element                       // OK
weak var elementReference2: Element! = element  // OK
strong var elementReference3: Element! = element        // Error
unowned var elementReference4: Element! = element       // Error

Ditto if you replace the implicitly unwrapped optionals with straight 
optionals. In other words, the rules for when you can use implicitly unwrapped 
optionals are the same as the rules for when you can use straight optionals.

Actually, however, although I think the last statement is correct, it seems 
that I was wrong to infer that elementReference1 is weak. One confusing thing 
about strong (which I’ve only just realised) is that it’s not actually a 
keyword in Swift! I previously assumed that because references default to 
strong, "var reference" is shorthand for "strong var reference". In fact 
“strong var reference” is illegal.

[Also, I think that the implicitly unwrapped optional (var capitalCity: City!) 
in the example in the Swift book does have to be a strong reference - because 
otherwise no-one is holding a retain count for capitalCity.]

Summarising - but please correct me if I’m wrong:

Strong references (no qualifier) can be optional or non-optional
Weak references (weak qualifier) must be optional (implicitly unwrapped or not)
Unowned references (unowned qualifier) must be non-optional

Jeremy

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to