How to annotate Objective-C APIs for use in Swift (e.g. return types)

前端 未结 2 1181
夕颜
夕颜 2020-12-08 22:39

According to the Xcode release notes, Apple has been \"auditing\" their existing APIs to remove implicitly unwrapped optionals. That means that instead of T!, t

相关标签:
2条回答
  • 2020-12-08 22:50

    I believe there's a way to do this at the moment. It looks like the information is being compiled to

    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator
    

    in files like

    UIKit.apinotesc 
    UIKit.swiftdoc 
    UIKit.swiftmodule
    

    The *.swiftmodule classes are generated by Xcode as part of the swift build but the additional information may be in the .apinotesc file, which there doesn't appear to be a documented form of generating it at the moment.

    However, the swift command has an -apinotes option, which is used to generate this. You can see from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator/UIKit.apinotesc that you can parse this with:

    xcrun swift -apinotes -binary-to-yaml  -o=- /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator/UIKit.apinotesc
    

    This generates a YAML file looking like:

    Classes:         
      - Name:            NSFileProviderExtension
        Availability:    available
        AvailabilityMsg: ''
        Methods:         
          - Selector:        'URLForItemWithPersistentIdentifier:'
            MethodKind:      Instance
            Nullability:     [ N ]
            NullabilityOfRet: U
            Availability:    available
            AvailabilityMsg: ''
    

    If I were a betting man (and I'm not), I'd say that the MethodKind determines whether it's an Instance or a Class and that the Nullability is being used by Swift to determine whether it's an optional or not. I would suspect:

    • U - (implicitly) unwrapped optional
    • O - optional
    • N - non-optional?

    These are wild guesses though.

    0 讨论(0)
  • 2020-12-08 22:56

    Xcode 6.3/Swift 1.2

    Xcode 6.3 added official support for annotating nullability in Objective-C.

    Nullability

    The nullability of a value can be declared by annotating the type with the keywords __nullable, __nonnull and __null_unspecified (the default). In properties and methods the keywords are nullable, nonnull and null_unspecified.

    Examples from the Xcode release notes

       - (void)registerNib:(nonnull UINib *)nib
    forCellReuseIdentifier:(nonnull NSString *)identifier;
    
    - (nullable UITableViewCell *)cellForRowAtIndexPath:(nonnull NSIndexPath)indexPath;
    
    @property (nonatomic, readwrite, retain, nullable) UIView *backgroundView;
    

    Changing the default

    null_unspecified (which translates to T!) is the default for all existing code. A useful feature is the ability to change the default for sections of your API.

    NS_ASSUME_NONNULL_BEGIN
    // nonnull is the default here
    NS_ASSUME_NONNULL_END
    

    This removes a lot of noise, since methods that accept and handle nil usually are the exception, not the rule. Personally, I would use this for all audited APIs.

    null_resettable

    null_resettable is an additional annotation that is used for the uncommon case where you can set a property to nil, but it will never be nil (because it resets to a default value).

     @property (nonatomic, retain, null_resettable) UIColor *tintColor;
    

    Personally, I would avoid this behavior for new code. The hybrid nature of such properties isn't a good fit for Swift.

    Xcode 7/Swift 2 (Beta)

    Xcode 7 adds support for annotating generic types in Objective-C.

    Generic type annotations for collections

    NSArray, NSSet and NSDictionary (which are automatically bridged to Swift's Array, Set and Dictionary can be annotated with the type of their contents.

    @property NSArray<NSString *> *stringArray;
    @property NSSet<NSString *> *stringSet;
    @property NSDictionary<NSString *, NSString *> *stringDict;
    

    There's also the __kindof keyword that tells the Objective-C compiler to be less strict and allow downcasting. But it doesn't affect the Swift side.

    Generic type annotations for custom classes

    @interface MyArray1<__covariant T> : NSObject
    - (void)addObject:(T)object;
    @end
    
    @interface MyArray2<__covariant T : NSObject *> : NSObject
    - (void)addObject:(T)object;
    @end
    
    @interface MyArray3<__covariant T : id<NSCopying>> : NSObject
    - (void)addObject:(T)object;
    @end
    

    The @implementation doesn't know about T and uses id/NSObject */id<NSCopying> as it always did.

    0 讨论(0)
提交回复
热议问题