Yep, I also admit the design of forbidding calling a setter before full
class initialization is reasonable and what's really annoying is the
inconsistency.

However, making @NSCopying attribute not subjects to the fact that
setters would not be invoked in initializers perhaps is viable too. In
the other words, assigning a value to a property whether or not by
calling a setter has no influence on whether @NSCopying semantic'd work:
copying should always take place after a property has been declared as
@NSCopying.

Jean-Daniel writes:

>> Le 28 janv. 2017 à 05:34, Torin Kwok via swift-evolution 
>> <swift-evolution@swift.org> a écrit :
>> 
>> Hello guys,
>> 
>> Note: This issue has been originally presented inswift-usersmailling list 
>> <https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20170123/004552.html>.
>>  And then I post it again here at the suggestion 
>> <https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20170123/004561.html>
>>  of Jordan Rose:
>> 
>> It might be reasonable to change this behavior, but it probably deserves a 
>> bit of discussion on swift-evolution; it's not 100%, for-sure a bug.
>> --- the original content follows this line ---
>> 
>> I encountered a strange behavior when I declared a property with the 
>> @NSCopying attribute:
>> 
>> // `Person` class inherits from `NSObject` class and conforms to `NSCopying` 
>> protocol
>> @NSCopying var employee: Person
>> and then assigned an external instance of Person class protocol to this 
>> property within the designated init methods:
>> 
>> // Designated initializer of `Department` class
>> init( employee externalEmployee: Person ) {
>>  self.employee = externalEmployee
>>  super.init()
>> 
>>  // Assertion would fail since Swift do not actually copy the value assigned 
>> to this property         
>>  // even though `self.employee` has been marked as `@NSCoyping`
>>  // assert( self.employee !== externalEmployee )
>>  }
>> If I indeed require the deep copying behavior during the init process, 
>> instead of taking advantage of @NSCopying attribute, I would have to invoke 
>> the copy() method manually:
>> 
>> init( employee externalEmployee: Person ) {
>>  // ...
>>  self.employee = externalEmployee.copy() as! Person  
>>  // ...
>>  }
>> In fact, what really makes me confusing is that @NSCopying semantic does 
>> work properly within the other parts of the class definition such as normal 
>> instance methods, or external scope. For instance, if we're assigning an 
>> external instance of Person to the self.employee proper of Department 
>> directly through setter rather than initializer:
>> 
>> department.employee = johnAppleseed
>> then self.employee property and johnAppleseed variable will no longer share 
>> the same underlying object now. In the other words, @NSCopying attribute 
>> makes sense.
>> 
>> After I looked through a great deal of results given by Google, and 
>> dicussions on StackOverflow, I finally end up with nothing helpful — the 
>> vast majority of articles, documentations as well as issues talking about 
>> this similar topics only focus on the basic concepts and effects of 
>> @NSCopying itself but do not mentioned this strange behavior at all — 
>> besides one radar descriping the same problem (rdar://21383959 
>> <rdar://21383959>) and a final conclusion mentioned in a guy's Gist comment: 
>> ... values set during initialization are not cloned ...
>> 
>> That is, @NSCopying semantic has no effect in initializers.
>> 
>> Then, what I want to figure out is the reason why @NSCopying semantic will 
>> become effectless implicitly whithin initializers of a class, and the 
>> special considerations behind this behavior, if any.
>> 
>> --- END ---
>> 
>> Jordan:
>> 
>> Your observation is correct: @NSCopying currently does not affect 
>> initializers. This is because accessing a property in an initializer always 
>> does direct access to the storage rather than going through the setter.
>> I have tested the identical logic in Objective-C and the NSCopying semantic 
>> works perfectly within Obj-C's class initializer.
>> 
> This is because Obj-C guarantee that all ivars are zero initialized and does 
> not enforce initializer safety (but forcing initialization of ivars before 
> calling other methods).
>
> Calling a setter (like any other method) before full class initialization is 
> unsafe as the setter may be overridden or simply customized, and may need to 
> access to the class or subclasses ivars.
>
> That said, I’m not sure what is the best way to solve that inconsistency.


-- 
Torin Kwok (郭桐)
OpenPGP/GnuPG: https://keybase.io/kwok
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to