So there are three questions:
- firstly, why access to user properties does not crash,
- second why there is an empty string instead of
nil one, - thirdly, why the assignment of a property (user class) is crashing
I will answer all of them :-)
1. Access to the "Users" properties
Swift uses the Objective-C message when accessing the properties of the Users class (suppose that - Users is an ObjC class, as shown in the debugger output, the base class is NSObject ). In the disassembly view, you can see this:
0x1000018be <+78>: movq 0x3e6e2b(%rip), %rsi ; "empId" .... 0x1000018d7 <+103>: callq 0x100361b10 ; symbol stub for: objc_msgSend
Since objc_msgSend supports nil messaging, the call is not interrupted.
2. Empty line Magic
When you call the Swift initializer from Objective-C, the bridge code creates the following:
0x100001f45 <+53>: callq 0x100021f50 ; static (extension in Foundation): ;Swift.String._unconditionallyBridgeFromObjectiveC (Swift.Optional<__ObjC.NSString>) -> Swift.String .... 0x100001f5b <+75>: callq 0x100001870 ; TestCalling.Tester.init (string : Swift.String, user : __ObjC.ObjCUser) -> TestCalling.Tester at SwiftClass.swift:14
The interesting part here is calling _unconditionallyBridgeFromObjectiveC . This will internally call the Swift.String _cocoaStringToSwiftString_NonASCII function and check the source code ( here, line 48 ), you can see the following
@inline(never) @_semantics("stdlib_binary_only") // Hide the CF dependency func _cocoaStringToSwiftString_NonASCII( _ source: _CocoaString ) -> String { let cfImmutableValue = _stdlib_binary_CFStringCreateCopy(source) let length = _stdlib_binary_CFStringGetLength(cfImmutableValue) let start = _stdlib_binary_CFStringGetCharactersPtr(cfImmutableValue) return String(_StringCore( baseAddress: start, count: length, elementShift: 1, hasCocoaBuffer: true, owner: unsafeBitCast(cfImmutableValue, to: Optional<AnyObject>.self))) }
The function always returns a new Swift.String object, in our case empty! So again, there are no glitches.
3. Access to properties
When accessing a custom property, for example. assigning it to a variable:
let x:SomeClass = object.someGetter;
the following happens:
The return value of someGetter will be saved ( objc_retainAutoreleasedReturnValue ) - this is not a failure
The returned object will be expanded implicitly, and then a message is issued
If x was a weak property or optional, the code will not crash. Even when using type inference, it doesn't crash (on my machine, fast 4):
let x = object.someGetter;
Is this because the type SomeClass? x is optional SomeClass? unless the property itself is declared as nonnull :
@property(nonatomic,strong, nonnull) SomeClass * object;