<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class="" style="font-family: LucidaGrande;"><p style="-webkit-print-color-adjust: exact; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2; margin-top: 0px !important;" class=""></p><p style="-webkit-print-color-adjust: exact; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2; margin-top: 0px !important;" class="">To better demonstrate the problems Iām describing, I gave out a simple demo running in Playground to reproduce that. Apart from that, I also attached a Playground file that contains identical content in this mail, for the convenience of examination.</p><div style="-webkit-print-color-adjust: exact; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class=""><pre class="line-numbers language-none" style="-webkit-print-color-adjust: exact; margin-top: 0.5em; background-image: linear-gradient(transparent 50%, rgba(69, 142, 209, 0.0392157) 50%); background-origin: content-box; background-clip: content-box; background-color: rgb(253, 253, 253); background-size: 3em 3em; border-width: 1px 1px 1px 10px; border-style: solid; border-color: rgb(204, 204, 204) rgb(204, 204, 204) rgb(204, 204, 204) rgb(53, 140, 203); font-size: 13px; line-height: 1.5; overflow: visible; padding: 0px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; word-spacing: normal; word-break: normal; word-wrap: normal; tab-size: 4; position: relative; box-shadow: rgb(53, 140, 203) -1px 0px 0px 0px, rgb(223, 223, 223) 0px 0px 0px 1px; box-sizing: border-box; counter-reset: linenumber 0; background-position: 0% 0%; background-repeat: initial initial;"><code class=" language-none" style="-webkit-print-color-adjust: exact; margin: 0px; padding: 0px 1em 0px 3.8em; border: none; background-image: none; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; word-spacing: normal; word-break: normal; word-wrap: normal; line-height: 1.5; tab-size: 4; max-height: inherit; height: 2052px; display: block; overflow: auto; position: relative; background-position: initial initial; background-repeat: initial initial;">import Foundation
class Person: NSObject,
NSCopying {
var firstName: String
var lastName: String
var job: String?
init( firstName: String, lastName: String, job: String? = nil ) {
self.firstName = firstName
self.lastName = lastName
self.job = job
super.init()
}
/// Conformance to <NSCopying> protocol
func copy( with zone: NSZone? = nil ) -> Any {
let theCopy = Person.init( firstName: firstName, lastName: lastName )
theCopy.job = job
return theCopy
}
override var description: String {
return "\(firstName) \(lastName)" + ( job != nil ? ", \(job!)" : "" )
}
}
let johnAppleseed = Person( firstName: "John", lastName: "Appleseed", job: "CEO" )
var refJohnAppleseed = johnAppleseed
// assigning wihtout copying semantic:
refJohnAppleseed.job = "Engineer"
// `cloneJohnAppleseed` and `johnAppleseed` have the identical `job` ...
refJohnAppleseed
johnAppleseed
// ... and the assertion **would not** fail:
assert( refJohnAppleseed === johnAppleseed )
// Assigning a copy of johnAppleseed to clonedJohnAppleseed,
// which was returned by `copy( zone: ) -> Any`
var clonedJohnAppleseed = johnAppleseed/* refJohnAppleseed is also okay */.copy() as! Person
clonedJohnAppleseed.job = "Designer"
johnAppleseed
// Alright you see, setting the job of `clonedJohnAppleseed` doesn't affect the
// job stored in `johnAppleseed`.
//: Up to now, everything goes right. However, when we begin introducing a new class consuming instances of `Person` class...
class Department: NSObject {
// Here, we're expecting that `self.employee` would automatically
// store the deeply-copied instance of `Person` class
@NSCopying var employee: Person
init( employee _ExternalPerson: Person ) {
// CAUTION! That's the key point:
// `self.employee` has been marked with `@NSCopying` attribute
// but what would take place here is only the shallow-copying.
// In the other words, `self.employee` will share identical underlying
// object with `_ExternalPerson`.
self.employee = _ExternalPerson
super.init()
// Assertion will definitely 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 !== employee ) */
}
override var description: String {
return "A Department: [ ( \(employee) ) ]"
}
}
let isaacNewton = Person( firstName: "Isaac", lastName: "Newton", job: "Mathematician" )
let lab = Department.init( employee: isaacNewton )
isaacNewton.job = "Astronomer"
lab.employee
// Oops! Setting the job of `isaacNewton` affects the job stored in `lab.employee`.
// That's an unexpected behavior as we have declared `employee` property as
// `@NSCopying`. Obviously, `@NSCopying` semantic became effectless implicitly
// within the initializer of `Department` class.
// For the moment, we're required to explictly invoke `copy()` method on instances
// that wanna be copied to make sure that classes' properties are able to store
// deeply-copied results during the initialization:
/* self.employee = _ExternalPerson.copy() as! Person */
//: What indeed makes me confusing is that...
// @NSCopying semantic does work properly within the scope other than initializers:
lab.employee = isaacNewton
isaacNewton.job = "Physicist"
lab.employee
// That's it! If we assigned external instance to `lab.employee`,
// `@NSCopying` semantic would be well respected.</code></pre></div><div class=""><br class=""></div></div></div><br class=""><div><blockquote type="cite" class=""><div class="">On 28 Jan 2017, at 12:34, Torin Kwok <<a href="mailto:torin@kwok.im" class="">torin@kwok.im</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><p style="-webkit-print-color-adjust: exact; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2; margin-top: 0px !important;" class="">Hello guys,</p><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class=""><strong style="-webkit-print-color-adjust: exact;" class="">Note:</strong> This issue has been <a href="https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20170123/004552.html" style="-webkit-print-color-adjust: exact; color: rgb(65, 131, 196);" class="">originally presented in <strong style="-webkit-print-color-adjust: exact;" class="">swift-users</strong> mailling list</a>. And then I post it again here at the <a href="https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20170123/004561.html" style="-webkit-print-color-adjust: exact; color: rgb(65, 131, 196);" class="">suggestion</a> of Jordan Rose:</p><blockquote style="-webkit-print-color-adjust: exact; margin: 15px 0px; border-left-width: 4px; border-left-style: solid; border-left-color: rgb(221, 221, 221); padding: 0px 15px; color: rgb(119, 119, 119); font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class=""><div style="-webkit-print-color-adjust: exact; margin: 0px;" class="">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.</div></blockquote><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class=""><strong style="-webkit-print-color-adjust: exact;" class="">--- the original content follows this line ---</strong></p><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class="">I encountered a strange behavior when I declared a property with the <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">@NSCopying</code> attribute:</p><div style="-webkit-print-color-adjust: exact; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class=""><pre style="-webkit-print-color-adjust: exact; margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="language-swift" style="-webkit-print-color-adjust: exact; margin: 0px; padding: 0px; border: none; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-position: initial initial; background-repeat: initial initial;">// `Person` class inherits from `NSObject` class and conforms to `NSCopying` protocol
@NSCopying var employee: Person</code></pre></div><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class="">and then assigned an external instance of <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">Person</code> class protocol to this property within the designated init methods:</p><div style="-webkit-print-color-adjust: exact; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class=""><pre style="-webkit-print-color-adjust: exact; margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="language-swift" style="-webkit-print-color-adjust: exact; margin: 0px; padding: 0px; border: none; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-position: initial initial; background-repeat: initial initial;">// 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 )
}</code></pre></div><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class="">If I indeed require the deep copying behavior during the init process, instead of taking advantage of <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">@NSCopying</code> attribute, I would have to invoke the <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">copy()</code> method manually:</p><div style="-webkit-print-color-adjust: exact; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class=""><pre style="-webkit-print-color-adjust: exact; margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="language-swift" style="-webkit-print-color-adjust: exact; margin: 0px; padding: 0px; border: none; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-position: initial initial; background-repeat: initial initial;">init( employee externalEmployee: Person ) {
// ...
self.employee = externalEmployee.copy() as! Person
// ...
}</code></pre></div><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class="">In fact, what really makes me confusing is that <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">@NSCopying</code> 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 <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">Person</code> to the <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">self.employee</code> proper of <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">Department</code> directly through setter rather than initializer:</p><div style="-webkit-print-color-adjust: exact; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class=""><pre style="-webkit-print-color-adjust: exact; margin-top: 15px; margin-bottom: 15px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class=""><code class="language-swift" style="-webkit-print-color-adjust: exact; margin: 0px; padding: 0px; border: none; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-position: initial initial; background-repeat: initial initial;">department.employee = johnAppleseed</code></pre></div><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class="">then <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">self.employee</code> property and <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">johnAppleseed</code> variable will no longer share the same underlying object now. In the other words, <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">@NSCopying</code> attribute makes sense.</p><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class="">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 <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">@NSCopying</code> itself but do not mentioned this strange behavior at all ā besides one radar descriping the same problem (<a href="rdar://21383959" style="-webkit-print-color-adjust: exact; color: rgb(65, 131, 196);" class="">rdar://21383959</a>) and a final conclusion mentioned in a guy's Gist comment: <strong style="-webkit-print-color-adjust: exact;" class="">... values set during initialization are not cloned ...</strong></p><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class="">That is, <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">@NSCopying</code> semantic has no effect in initializers.</p><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class="">Then, what I want to figure out is the reason why <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">@NSCopying</code> semantic will become effectless implicitly whithin initializers of a class, and the special considerations behind this behavior, if any.</p><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class=""><strong style="-webkit-print-color-adjust: exact;" class="">--- END ---</strong></p><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class="">Jordan:</p><blockquote style="-webkit-print-color-adjust: exact; margin: 15px 0px; border-left-width: 4px; border-left-style: solid; border-left-color: rgb(221, 221, 221); padding: 0px 15px; color: rgb(119, 119, 119); font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class=""><div style="-webkit-print-color-adjust: exact; margin: 0px;" class="">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.</div></blockquote><p style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2;" class="">I have tested the identical logic in Objective-C and the <code style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: nowrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px;" class="">NSCopying</code> semantic works perfectly within Obj-C's class initializer.</p><p style="-webkit-print-color-adjust: exact; margin-top: 15px; margin-right: 0px; margin-left: 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2; margin-bottom: 0px !important;" class="">I have no idea whether it's a bug or special consideration. After all, as a special consideration, it seems too strange that this behavior has not been obviously documented.</p><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><font face="Helvetica" class=""><span style="font-size: 14px;" class="">Best Regards,</span></font></div><div class=""><font face="Helvetica" class=""><span style="font-size: 14px;" class="">Torin Kwok</span></font></div><div class=""><br class=""></div><div class=""><br class=""></div></div></div></blockquote></div><br class=""></body></html>