@objc public class Tester: NSObject { private var name: String private var user: Users init(string:String,user: Users) { print(user.empId) print(user.name) self.user = user self.name = string super.init() } }
我从Obj C调用初始化程序,如下所示:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. Nsstring * nilString = nil; Users * nilUser = nil; Tester * test = [[Tester alloc] initWithString:nilString user:nilUser]; return YES; }
在这里,我将nil参数传递给Swift初始化器.理想情况下,我希望这会崩溃,因为初始化程序只接受非零值.
但实际发生的是,当执行点到达初始化程序内部时,会创建新的参数对象:
nil字符串变为“”,而nil的User变量现在指向一个对象.
但是对于像这样的房产
@property(nonatomic,strong) SomeClass * object;
哪里
object = nil;
当我从swift调用这个对象时,
let x = object.someGetter;
这崩溃了.
有一次,如果我将nil传递给某些非null,它会起作用,而在另一点上,它会崩溃.为什么存在这种奇怪的行为?如果由于某些原因,我的参数是nil,并传递给nonnull,我希望这会崩溃.这样我就能解决问题.
编辑:这变得如此意外,进一步尝试使用此代码.
字符串参数实际上是字符串,但是User显示未初始化,因此对字符串的操作运行良好,但是用户对象接受了更改,但没有显示它们.
解决方法
>首先,为什么访问用户属性不会崩溃,
>第二,为什么有一个空字符串而不是一个空字符串,
>第三,为什么分配属性(自定义类)崩溃
我会回答所有这些:-)
1.访问“用户”属性
当访问Users类的属性时,Swift使用Objective C消息传递(我假设 – 用户是调试器输出中看到的ObjC-Class;基类NSObject).
在反汇编视图中,可以看到:
0x1000018be <+78>: movq 0x3e6e2b(%rip),%rsi ; "empId" .... 0x1000018d7 <+103>: callq 0x100361b10 ; symbol stub for: objc_msgSend
由于objc_msgSend支持nil消息传递,因此调用不会失败.
2.空字符串魔法
从Objective C调用Swift初始化程序时,桥接代码会创建以下内容:
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
这里有趣的部分是_unconditionallyBridgeFromObjectiveC调用.这将在内部调用Swift.String函数_cocoaStringToSwiftString_NonASCII,并检查源代码(here,line 48),您可以看到以下内容:
@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))) }
该函数总是返回一个新的Swift.String对象,在我们的例子中是一个空对象!所以,再没有崩溃.
3.财产准入
访问自定义属性时,例如将其分配给变量:
let x:SomeClass = object.someGetter;
发生以下情况:
> someGetter的返回值将被保留(objc_retainAutoreleasedReturnValue) – 这不会崩溃
>返回的对象将被隐式解包 – 然后崩溃
如果x是弱属性或可选,则代码不会崩溃.即使使用类型推断,它也不会崩溃(在我的机器上,swift 4):
let x = object.someGetter;
这是因为推断的x类型是可选的SomeClass?除非属性本身被声明为nonnull:
@property(nonatomic,strong,nonnull) SomeClass * object;