声明一个协议 @objc 和让它在纯 Swift 中符合 NSObjectProtocol 有什么区别?
What is the difference between declaring a protocol @objc and having it conform to NSObjectProtocol in pure Swift?
考虑两个 Swift 协议:
@objc protocol SomeProtocol { }
protocol SomeOtherProtocol: NSObjectProtocol { }
声明 Swift 协议 @objc
或使其符合 NSObjectProtocol
有什么区别?我知道任何不 @objc
的协议都不会桥接到 Objective-C,但是这两个声明在纯 Swift 应用程序中有什么区别?据我了解,@objc
应该通过顶级 SwiftObject
.
使 SomeProtocol
符合 NSObjectProtocol
我发现的一个区别是,使协议符合 NSObjectProtocol
会将 Objective-C 符号信息加载到已编译的 Swift 二进制文件中。请参阅下面生成的程序集:
l__PROTOCOL_NSObject:
.quad 0
.quad L___unnamed_2
.quad 0
.quad l__PROTOCOL_INSTANCE_METHODS_NSObject
.quad 0
.quad l__PROTOCOL_INSTANCE_METHODS_OPT_NSObject
.quad 0
.quad l__PROTOCOL_PROPERTIES_NSObject
.long 80
.long 0
.quad l__PROTOCOL_METHOD_TYPES_NSObject
.private_extern l_OBJC_LABEL_PROTOCOL_$_NSObject
.section __DATA,__objc_protolist,coalesced,no_dead_strip
.globl l_OBJC_LABEL_PROTOCOL_$_NSObject
.weak_definition l_OBJC_LABEL_PROTOCOL_$_NSObject
.align 3
l_OBJC_LABEL_PROTOCOL_$_NSObject:
.quad l__PROTOCOL_NSObject
.private_extern l_OBJC_PROTOCOL_REFERENCE_$_NSObject
.section __DATA,__objc_protorefs,coalesced,no_dead_strip
.globl l_OBJC_PROTOCOL_REFERENCE_$_NSObject
.weak_definition l_OBJC_PROTOCOL_REFERENCE_$_NSObject
.align 3
l_OBJC_PROTOCOL_REFERENCE_$_NSObject:
.quad l__PROTOCOL_NSObject
.section __DATA,__const
.align 3
l___unnamed_3:
.quad 1
.quad l__PROTOCOL_NSObject
.globl __TMp3obj10MyProtocol
.align 3
__TMp3obj10MyProtocol:
.quad 0
.quad L___unnamed_1
.quad l___unnamed_3
.quad 0
.quad 0
.quad 0
.quad 0
.quad 0
.long 72
.long 5
# ...
# __swift_FORCE_LOAD_ of linked libraries
__swift_FORCE_LOAD_$_swiftCoreGraphics_$_obj:
.quad __swift_FORCE_LOAD_$_swiftCoreGraphics
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(isEqual:)":
.asciz "isEqual:"
.section __TEXT,__cstring,cstring_literals
L___unnamed_4:
.asciz "c24@0:8@16"
L___unnamed_5:
.asciz "hash"
L___unnamed_6:
.asciz "Tq,N,R"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(hash)":
.asciz "hash"
.section __TEXT,__cstring,cstring_literals
L___unnamed_7:
.asciz "q16@0:8"
L___unnamed_8:
.asciz "superclass"
L___unnamed_9:
.asciz "T#,N,R"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(superclass)":
.asciz "superclass"
.section __TEXT,__cstring,cstring_literals
L___unnamed_10:
.asciz "#16@0:8"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(class)":
.asciz "class"
"L_selector_data(self)":
.asciz "self"
.section __TEXT,__cstring,cstring_literals
L___unnamed_11:
.asciz "@16@0:8"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(performSelector:)":
.asciz "performSelector:"
.section __TEXT,__cstring,cstring_literals
L___unnamed_12:
.asciz "^@24@0:8:16"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(performSelector:withObject:)":
.asciz "performSelector:withObject:"
.section __TEXT,__cstring,cstring_literals
L___unnamed_13:
.asciz "^@32@0:8:16@24"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(performSelector:withObject:withObject:)":
.asciz "performSelector:withObject:withObject:"
.section __TEXT,__cstring,cstring_literals
.align 4
L___unnamed_14:
.asciz "^@40@0:8:16@24@32"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(isProxy)":
.asciz "isProxy"
.section __TEXT,__cstring,cstring_literals
L___unnamed_15:
.asciz "c16@0:8"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(isKindOfClass:)":
.asciz "isKindOfClass:"
.section __TEXT,__cstring,cstring_literals
L___unnamed_16:
.asciz "c24@0:8#16"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(isMemberOfClass:)":
.asciz "isMemberOfClass:"
"L_selector_data(conformsToProtocol:)":
.asciz "conformsToProtocol:"
.section __TEXT,__cstring,cstring_literals
.align 4
L___unnamed_17:
.asciz "c24@0:8@\"Protocol\"16"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(respondsToSelector:)":
.asciz "respondsToSelector:"
.section __TEXT,__cstring,cstring_literals
L___unnamed_18:
.asciz "c24@0:8:16"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(retain)":
.asciz "retain"
"L_selector_data(release)":
.asciz "release"
.section __TEXT,__cstring,cstring_literals
L___unnamed_19:
.asciz "v16@0:8"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(autorelease)":
.asciz "autorelease"
"L_selector_data(retainCount)":
.asciz "retainCount"
"L_selector_data(zone)":
.asciz "zone"
.section __TEXT,__cstring,cstring_literals
L___unnamed_20:
.asciz "^v16@0:8"
L___unnamed_21:
.asciz "description"
.align 4
L___unnamed_22:
.asciz "T@\"NSString\",N,R"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(description)":
.asciz "description"
.section __TEXT,__cstring,cstring_literals
.align 4
L___unnamed_23:
.asciz "@\"NSString\"16@0:8"
.align 4
L___unnamed_24:
.asciz "debugDescription"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(debugDescription)":
.asciz "debugDescription"
.section __TEXT,__cstring,cstring_literals
L___unnamed_2:
.asciz "NSObject"
.section __DATA,__objc_const
.align 3
l__PROTOCOL_INSTANCE_METHODS_NSObject:
.long 24
.long 19
.quad "L_selector_data(isEqual:)"
.quad L___unnamed_4
.quad 0
.quad "L_selector_data(hash)"
.quad L___unnamed_7
.quad 0
.quad "L_selector_data(superclass)"
.quad L___unnamed_10
.quad 0
.quad "L_selector_data(class)"
.quad L___unnamed_10
.quad 0
.quad "L_selector_data(self)"
.quad L___unnamed_11
.quad 0
.quad "L_selector_data(performSelector:)"
.quad L___unnamed_12
.quad 0
.quad "L_selector_data(performSelector:withObject:)"
.quad L___unnamed_13
.quad 0
.quad "L_selector_data(performSelector:withObject:withObject:)"
.quad L___unnamed_14
.quad 0
.quad "L_selector_data(isProxy)"
.quad L___unnamed_15
.quad 0
.quad "L_selector_data(isKindOfClass:)"
.quad L___unnamed_16
.quad 0
.quad "L_selector_data(isMemberOfClass:)"
.quad L___unnamed_16
.quad 0
.quad "L_selector_data(conformsToProtocol:)"
.quad L___unnamed_4
.quad 0
.quad "L_selector_data(respondsToSelector:)"
.quad L___unnamed_18
.quad 0
.quad "L_selector_data(retain)"
.quad L___unnamed_11
.quad 0
.quad "L_selector_data(release)"
.quad L___unnamed_19
.quad 0
.quad "L_selector_data(autorelease)"
.quad L___unnamed_11
.quad 0
.quad "L_selector_data(retainCount)"
.quad L___unnamed_7
.quad 0
.quad "L_selector_data(zone)"
.quad L___unnamed_20
.quad 0
.quad "L_selector_data(description)"
.quad L___unnamed_11
.quad 0
.align 3
l__PROTOCOL_INSTANCE_METHODS_OPT_NSObject:
.long 24
.long 1
.quad "L_selector_data(debugDescription)"
.quad L___unnamed_11
.quad 0
.align 3
l__PROTOCOL_PROPERTIES_NSObject:
.long 16
.long 4
.quad L___unnamed_5
.quad L___unnamed_6
.quad L___unnamed_8
.quad L___unnamed_9
.quad L___unnamed_21
.quad L___unnamed_22
.quad L___unnamed_24
.quad L___unnamed_22
.align 3
l__PROTOCOL_METHOD_TYPES_NSObject:
.quad L___unnamed_4
.quad L___unnamed_7
.quad L___unnamed_10
.quad L___unnamed_10
.quad L___unnamed_11
.quad L___unnamed_12
.quad L___unnamed_13
.quad L___unnamed_14
.quad L___unnamed_15
.quad L___unnamed_16
.quad L___unnamed_16
.quad L___unnamed_17
.quad L___unnamed_18
.quad L___unnamed_11
.quad L___unnamed_19
.quad L___unnamed_11
.quad L___unnamed_7
.quad L___unnamed_20
.quad L___unnamed_23
.quad L___unnamed_23
.no_dead_strip __TMp3obj10MyProtocol
当声明协议@objc
时,这些符号没有加载,我认为这项工作被转移到Swift模块的Objective-C头文件。
MyApp-Swift.h
SWIFT_PROTOCOL("_TtP15MyApp12SomeProtocol_")
@protocol SomeProtocol
@end
每个协议生成的程序集之间的完整差异 here。
存在差异,但可能有些细微差别。简而言之,@objc
为您提供了 optional
,您不需要并且不适用于结构。另一方面,NSObjectProtocol
本质上只是将实现限制为 NSObject
.
的子classes
将协议注释为 @objc
意味着它已在 Objective-C 运行时注册,允许协议具有运行时特定的功能,即可选要求。这也意味着该协议不能用在结构上,但它可以用在 any class 上,同样,包含它的字典和数组可以桥接到 NSDictionary 和 NSArray。从纯粹的 swift 角度来看,您可能没有理由 需要 这样做,因为该功能已在很大程度上被协议扩展所取代。
另一方面,当协议扩展 NSObjectProtocol
时,它仍然可以用在结构上 但是 该结构必须实现所有预期的方法NSObjectProtocol
。这可能是一项艰巨的任务。从实际的角度来看,它实际上只是迫使您使实现 SomeOtherProtocol
的 class 成为链上某处 NSObject
的子class。
考虑两个 Swift 协议:
@objc protocol SomeProtocol { }
protocol SomeOtherProtocol: NSObjectProtocol { }
声明 Swift 协议 @objc
或使其符合 NSObjectProtocol
有什么区别?我知道任何不 @objc
的协议都不会桥接到 Objective-C,但是这两个声明在纯 Swift 应用程序中有什么区别?据我了解,@objc
应该通过顶级 SwiftObject
.
SomeProtocol
符合 NSObjectProtocol
我发现的一个区别是,使协议符合 NSObjectProtocol
会将 Objective-C 符号信息加载到已编译的 Swift 二进制文件中。请参阅下面生成的程序集:
l__PROTOCOL_NSObject:
.quad 0
.quad L___unnamed_2
.quad 0
.quad l__PROTOCOL_INSTANCE_METHODS_NSObject
.quad 0
.quad l__PROTOCOL_INSTANCE_METHODS_OPT_NSObject
.quad 0
.quad l__PROTOCOL_PROPERTIES_NSObject
.long 80
.long 0
.quad l__PROTOCOL_METHOD_TYPES_NSObject
.private_extern l_OBJC_LABEL_PROTOCOL_$_NSObject
.section __DATA,__objc_protolist,coalesced,no_dead_strip
.globl l_OBJC_LABEL_PROTOCOL_$_NSObject
.weak_definition l_OBJC_LABEL_PROTOCOL_$_NSObject
.align 3
l_OBJC_LABEL_PROTOCOL_$_NSObject:
.quad l__PROTOCOL_NSObject
.private_extern l_OBJC_PROTOCOL_REFERENCE_$_NSObject
.section __DATA,__objc_protorefs,coalesced,no_dead_strip
.globl l_OBJC_PROTOCOL_REFERENCE_$_NSObject
.weak_definition l_OBJC_PROTOCOL_REFERENCE_$_NSObject
.align 3
l_OBJC_PROTOCOL_REFERENCE_$_NSObject:
.quad l__PROTOCOL_NSObject
.section __DATA,__const
.align 3
l___unnamed_3:
.quad 1
.quad l__PROTOCOL_NSObject
.globl __TMp3obj10MyProtocol
.align 3
__TMp3obj10MyProtocol:
.quad 0
.quad L___unnamed_1
.quad l___unnamed_3
.quad 0
.quad 0
.quad 0
.quad 0
.quad 0
.long 72
.long 5
# ...
# __swift_FORCE_LOAD_ of linked libraries
__swift_FORCE_LOAD_$_swiftCoreGraphics_$_obj:
.quad __swift_FORCE_LOAD_$_swiftCoreGraphics
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(isEqual:)":
.asciz "isEqual:"
.section __TEXT,__cstring,cstring_literals
L___unnamed_4:
.asciz "c24@0:8@16"
L___unnamed_5:
.asciz "hash"
L___unnamed_6:
.asciz "Tq,N,R"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(hash)":
.asciz "hash"
.section __TEXT,__cstring,cstring_literals
L___unnamed_7:
.asciz "q16@0:8"
L___unnamed_8:
.asciz "superclass"
L___unnamed_9:
.asciz "T#,N,R"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(superclass)":
.asciz "superclass"
.section __TEXT,__cstring,cstring_literals
L___unnamed_10:
.asciz "#16@0:8"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(class)":
.asciz "class"
"L_selector_data(self)":
.asciz "self"
.section __TEXT,__cstring,cstring_literals
L___unnamed_11:
.asciz "@16@0:8"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(performSelector:)":
.asciz "performSelector:"
.section __TEXT,__cstring,cstring_literals
L___unnamed_12:
.asciz "^@24@0:8:16"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(performSelector:withObject:)":
.asciz "performSelector:withObject:"
.section __TEXT,__cstring,cstring_literals
L___unnamed_13:
.asciz "^@32@0:8:16@24"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(performSelector:withObject:withObject:)":
.asciz "performSelector:withObject:withObject:"
.section __TEXT,__cstring,cstring_literals
.align 4
L___unnamed_14:
.asciz "^@40@0:8:16@24@32"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(isProxy)":
.asciz "isProxy"
.section __TEXT,__cstring,cstring_literals
L___unnamed_15:
.asciz "c16@0:8"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(isKindOfClass:)":
.asciz "isKindOfClass:"
.section __TEXT,__cstring,cstring_literals
L___unnamed_16:
.asciz "c24@0:8#16"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(isMemberOfClass:)":
.asciz "isMemberOfClass:"
"L_selector_data(conformsToProtocol:)":
.asciz "conformsToProtocol:"
.section __TEXT,__cstring,cstring_literals
.align 4
L___unnamed_17:
.asciz "c24@0:8@\"Protocol\"16"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(respondsToSelector:)":
.asciz "respondsToSelector:"
.section __TEXT,__cstring,cstring_literals
L___unnamed_18:
.asciz "c24@0:8:16"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(retain)":
.asciz "retain"
"L_selector_data(release)":
.asciz "release"
.section __TEXT,__cstring,cstring_literals
L___unnamed_19:
.asciz "v16@0:8"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(autorelease)":
.asciz "autorelease"
"L_selector_data(retainCount)":
.asciz "retainCount"
"L_selector_data(zone)":
.asciz "zone"
.section __TEXT,__cstring,cstring_literals
L___unnamed_20:
.asciz "^v16@0:8"
L___unnamed_21:
.asciz "description"
.align 4
L___unnamed_22:
.asciz "T@\"NSString\",N,R"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(description)":
.asciz "description"
.section __TEXT,__cstring,cstring_literals
.align 4
L___unnamed_23:
.asciz "@\"NSString\"16@0:8"
.align 4
L___unnamed_24:
.asciz "debugDescription"
.section __TEXT,__objc_methname,cstring_literals
"L_selector_data(debugDescription)":
.asciz "debugDescription"
.section __TEXT,__cstring,cstring_literals
L___unnamed_2:
.asciz "NSObject"
.section __DATA,__objc_const
.align 3
l__PROTOCOL_INSTANCE_METHODS_NSObject:
.long 24
.long 19
.quad "L_selector_data(isEqual:)"
.quad L___unnamed_4
.quad 0
.quad "L_selector_data(hash)"
.quad L___unnamed_7
.quad 0
.quad "L_selector_data(superclass)"
.quad L___unnamed_10
.quad 0
.quad "L_selector_data(class)"
.quad L___unnamed_10
.quad 0
.quad "L_selector_data(self)"
.quad L___unnamed_11
.quad 0
.quad "L_selector_data(performSelector:)"
.quad L___unnamed_12
.quad 0
.quad "L_selector_data(performSelector:withObject:)"
.quad L___unnamed_13
.quad 0
.quad "L_selector_data(performSelector:withObject:withObject:)"
.quad L___unnamed_14
.quad 0
.quad "L_selector_data(isProxy)"
.quad L___unnamed_15
.quad 0
.quad "L_selector_data(isKindOfClass:)"
.quad L___unnamed_16
.quad 0
.quad "L_selector_data(isMemberOfClass:)"
.quad L___unnamed_16
.quad 0
.quad "L_selector_data(conformsToProtocol:)"
.quad L___unnamed_4
.quad 0
.quad "L_selector_data(respondsToSelector:)"
.quad L___unnamed_18
.quad 0
.quad "L_selector_data(retain)"
.quad L___unnamed_11
.quad 0
.quad "L_selector_data(release)"
.quad L___unnamed_19
.quad 0
.quad "L_selector_data(autorelease)"
.quad L___unnamed_11
.quad 0
.quad "L_selector_data(retainCount)"
.quad L___unnamed_7
.quad 0
.quad "L_selector_data(zone)"
.quad L___unnamed_20
.quad 0
.quad "L_selector_data(description)"
.quad L___unnamed_11
.quad 0
.align 3
l__PROTOCOL_INSTANCE_METHODS_OPT_NSObject:
.long 24
.long 1
.quad "L_selector_data(debugDescription)"
.quad L___unnamed_11
.quad 0
.align 3
l__PROTOCOL_PROPERTIES_NSObject:
.long 16
.long 4
.quad L___unnamed_5
.quad L___unnamed_6
.quad L___unnamed_8
.quad L___unnamed_9
.quad L___unnamed_21
.quad L___unnamed_22
.quad L___unnamed_24
.quad L___unnamed_22
.align 3
l__PROTOCOL_METHOD_TYPES_NSObject:
.quad L___unnamed_4
.quad L___unnamed_7
.quad L___unnamed_10
.quad L___unnamed_10
.quad L___unnamed_11
.quad L___unnamed_12
.quad L___unnamed_13
.quad L___unnamed_14
.quad L___unnamed_15
.quad L___unnamed_16
.quad L___unnamed_16
.quad L___unnamed_17
.quad L___unnamed_18
.quad L___unnamed_11
.quad L___unnamed_19
.quad L___unnamed_11
.quad L___unnamed_7
.quad L___unnamed_20
.quad L___unnamed_23
.quad L___unnamed_23
.no_dead_strip __TMp3obj10MyProtocol
当声明协议@objc
时,这些符号没有加载,我认为这项工作被转移到Swift模块的Objective-C头文件。
MyApp-Swift.h
SWIFT_PROTOCOL("_TtP15MyApp12SomeProtocol_")
@protocol SomeProtocol
@end
每个协议生成的程序集之间的完整差异 here。
存在差异,但可能有些细微差别。简而言之,@objc
为您提供了 optional
,您不需要并且不适用于结构。另一方面,NSObjectProtocol
本质上只是将实现限制为 NSObject
.
将协议注释为 @objc
意味着它已在 Objective-C 运行时注册,允许协议具有运行时特定的功能,即可选要求。这也意味着该协议不能用在结构上,但它可以用在 any class 上,同样,包含它的字典和数组可以桥接到 NSDictionary 和 NSArray。从纯粹的 swift 角度来看,您可能没有理由 需要 这样做,因为该功能已在很大程度上被协议扩展所取代。
另一方面,当协议扩展 NSObjectProtocol
时,它仍然可以用在结构上 但是 该结构必须实现所有预期的方法NSObjectProtocol
。这可能是一项艰巨的任务。从实际的角度来看,它实际上只是迫使您使实现 SomeOtherProtocol
的 class 成为链上某处 NSObject
的子class。