В чем разница между объявлением протокола @objc и его соответствием NSObjectProtocol в чистом Swift?

Рассмотрим два протокола Swift:

@objc protocol SomeProtocol { }

protocol SomeOtherProtocol: NSObjectProtocol { }

В чем разница между объявлением протокола Swift @objc или его соответствием NSObjectProtocol? Я знаю, что любой протокол, который не поддерживает @objc, не будет связан с Objective-C, но в чем разница между этими двумя объявлениями в чистом приложении Swift? Насколько я понимаю, @objc должно соответствовать SomeProtocol до NSObjectProtocol через верхний уровень SwiftObject.


person JAL    schedule 25.05.2016    source источник
comment
В чистом Swift, зачем вам использовать @objc?   -  person jtbandes    schedule 25.05.2016
comment
Я не знаю, я спрашиваю, эквивалентны ли эти два объявления. Я просматривал сгенерированную сборку, и оказалось, что соответствие протокола NSObjectProtocol загружает информацию о символах Objective-C, а простое добавление @objc — нет.   -  person JAL    schedule 25.05.2016


Ответы (2)


Отличия есть, но они могут быть немного нюансированы. Короче говоря, @objc дает вам optional, который вам не нужен и не работает со структурами. NSObjectProtocol, с другой стороны, по существу просто ограничивает реализации, чтобы они были подклассами NSObject.

Аннотирование протокола как @objc означает, что он зарегистрирован в среде выполнения Objective-C, что позволяет протоколу иметь специфические функции среды выполнения, а именно необязательные требования. Это также означает, что протокол нельзя использовать в структуре, но его можно использовать в любом классе, а также словари и массивы, содержащие его, можно связать с NSDictionary и NSArray. С точки зрения чистой скорости, вероятно, нет причин, по которым вам нужно это делать, поскольку эта функция в значительной степени была вытеснена расширениями протокола.

С другой стороны, когда протокол расширяет NSObjectProtocol, его все еще можно использовать в структуре но, эта структура должна будет реализовать все методы, ожидаемые от NSObjectProtocol. Это может быть непростой задачей. С практической точки зрения это просто заставляет вас делать классы, реализующие SomeOtherProtocol, подклассами NSObject где-то вверх по цепочке.

person Brian Nickel♦    schedule 25.05.2016
comment
Спасибо, Брайан, это как раз тот ответ, который я искал. - person JAL; 25.05.2016

Одно отличие, которое я обнаружил, заключается в том, что соответствие протокола 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 эти символы не загружаются, и я думаю, что эта работа переносится в заголовок Objective-C модуля Swift.

MyApp-Swift.h

SWIFT_PROTOCOL("_TtP15MyApp12SomeProtocol_")
@protocol SomeProtocol
@end

Полная разница между сгенерированными сборками каждого протокола здесь.

person JAL    schedule 25.05.2016