-
Refine Objective-C frameworks for Swift
Fine-tune your Objective-C headers to work beautifully in Swift. We'll show you how to take an unwieldy Objective-C framework and transform it into an API that feels right at home. Learn about the suite of annotations you can use to provide richer type information, more idiomatic names, and better errors to Swift. And discover Objective-C conventions you might not have known about that are key to a well-behaved Swift API.
To get the most out of this session, you should be familiar with Swift and Objective-C.
For more on working with Swift and Objective-C, check out our Developer Documentation and take a look at “Behind the Scenes of the Xcode Build Process” from WWDC18.Recursos
-
Buscar este video…
-
-
4:43 - Describe nullability to control optionals (method and property annotations)
// // SKMission.h // // View the generated interface to see how Swift imports this header. // #import <Foundation/Foundation.h> @interface SKMission : NSObject @property (readonly, nullable) NSString *name; - (nonnull instancetype)initWithName:(nullable NSString *)name; @end -
6:53 - Describe nullability to control optionals (ASSUME_NONNULL blocks)
// // SKMission.h // // View the generated interface to see how Swift imports this header. // #import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface SKMission : NSObject @property (readonly, nullable) NSString *name; - (instancetype)initWithName:(nullable NSString *)name; @end NS_ASSUME_NONNULL_END -
7:14 - Describe nullability to control optionals (qualifiers)
// // Misc.h // // View the generated interface to see how Swift imports this header. // #import <Foundation/Foundation.h> NSString * _Nonnull const SKRocketSaturnV; @interface ResourceValueContainer : NSObject - (BOOL)getResourceValue:(id _Nullable * _Nonnull)outValue error:(NSError**)error; @end -
8:09 - Finding nullability mistakes with Objective-C tools
// // SKMission.h // #import <Foundation/Foundation.h> @interface SKMission : NSObject @property (strong, nonnull) NSString *rocket; @property (strong, nonnull) NSString *capsule; @end // // SKRocket.h // #import <Foundation/Foundation.h> extern NSString *_Nonnull const SKRocketSaturnV; // // SKMission.m // // Try building this file and then try analyzing it. // #import "SKRocket.h" #import "SKMission.h" @implementation SKMission @end @interface SKMissionConfigurator : NSObject @property (strong, nullable) SKMission *mission; @end @implementation SKMissionConfigurator - (void)testBadUseWithWarning { [self.mission setCapsule:nil]; } - (void)testBadUseWithStaticAnalyzer:(BOOL)missionIsSkylab1 { NSString *capsule = nil; if (!missionIsSkylab1) { capsule = SKCapsuleApolloCSM; } self.mission.capsule = capsule; } @end -
11:07 - Use Objective-C generics for Foundation types
// // SKAstronaut.h // #import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface SKAstronaut : NSObject // Stub declaration @end NS_ASSUME_NONNULL_END // // SKMission.h // // View the generated interface to see how Swift imports this header. // #import <Foundation/Foundation.h> #import <SpaceKit/SKAstronaut.h> NS_ASSUME_NONNULL_BEGIN @interface SKMission : NSObject @property (readonly) NSArray<SKAstronaut *> *crew; @end NS_ASSUME_NONNULL_END -
11:33 - Use Int for numbers—unsigned types are for bitwise operations
// // SKRocket.h // // View the generated interface to see how Swift imports this header. // #import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN NSInteger SKRocketStageCount(NSString *); NS_ASSUME_NONNULL_END // // NSData+xor.h // // View the generated interface to see how Swift imports this header. // #import <Foundation/Foundation.h> @interface NSData (xor) - (void)xorWithByte:(uint8_t)value; @end -
13:23 - Strengthen stringly-typed constants
// // SKRocket.h // // View the generated interface to see how Swift imports this header. // #import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN typedef NSString *SKRocket NS_STRING_ENUM; extern SKRocket const SKRocketAtlas; extern SKRocket const SKRocketTitanII; extern SKRocket const SKRocketSaturnIB; extern SKRocket const SKRocketSaturnV; NSInteger SKRocketStageCount(SKRocket); NS_ASSUME_NONNULL_END -
15:24 - Specify initializer behavior
// // SKAstronaut.h // // View the generated interface to see how Swift imports this header. // #import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface SKAstronaut : NSObject - (instancetype)initWithNameComponents:(NSPersonNameComponents *)name NS_DESIGNATED_INITIALIZER; - (instancetype)initWithName:(NSString *)name; - (instancetype)init NS_UNAVAILABLE; @property (strong, readwrite) NSPersonNameComponents *nameComponents; @property (readonly) NSString *name; @end NS_ASSUME_NONNULL_END // // SKAstronaut.m // #import "SKAstronaut.h" @interface SKAstronaut () @property (class, readonly, strong) NSPersonNameComponentsFormatter *nameFormatter; @end @implementation SKAstronaut - (id)initWithNameComponents:(NSPersonNameComponents *)name { self = [super init]; if (self) { _name = name; } return self; } - (id)initWithName:(NSString *)name { return [self initWithNameComponents:[SKAstronaut _componentsFromName:name]]; } - (id)init { [self doesNotRecognizeSelector:_cmd]; return nil; } - (NSString *)name { return [SKAstronaut.nameFormatter stringFromPersonNameComponents:self.nameComponents]; } + (NSPersonNameComponents*)_componentsFromName:(NSString*)name { return [self.nameFormatter personNameComponentsFromString:name]; } + (NSPersonNameComponentsFormatter *)nameFormatter { static NSPersonNameComponentsFormatter *singleton; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ singleton = [NSPersonNameComponentsFormatter new]; }); return singleton; } @end -
20:00 - Follow the error handling convention
// // SKMission.h // // View the generated interface to see how Swift imports this header. // #import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface SKMission : NSObject /// \returns \c YES if saved; \c NO with non-nil \c *error if failed to save; /// \c NO with nil \c *error` if nothing needed to be saved. - (BOOL)saveToURL:(NSURL *)url error:(NSError **)error NS_SWIFT_NOTHROW DEPRECATED_ATTRIBUTE; /// @param[out] wasDirty If provided, set to \c YES if the file needed to be /// saved or \c NO if there weren’t any changes to save. - (BOOL)saveToURL:(NSURL *)url wasDirty:(nullable BOOL *)wasDirty error:(NSError **)error; @end NS_ASSUME_NONNULL_END -
22:40 - Refine an Objective-C API for Swift users
// // SKMission.h // // View the generated interface to see how Swift imports this header. // #import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface SKMission : NSObject /// \returns \c YES if saved; \c NO with non-nil \c *error if failed to save; /// \c NO with nil \c *error` if nothing needed to be saved. - (BOOL)saveToURL:(NSURL *)url error:(NSError **)error NS_SWIFT_NOTHROW DEPRECATED_ATTRIBUTE; /// @param[out] wasDirty If provided, set to \c YES if the file needed to be /// saved or \c NO if there weren’t any changes to save. - (BOOL)saveToURL:(NSURL *)url wasDirty:(nullable BOOL *)wasDirty error:(NSError **)error NS_REFINED_FOR_SWIFT; @end NS_ASSUME_NONNULL_END // // SwiftExtensions.swift // import Foundation extension SKMission { public func save(to url: URL) throws -> Bool { var wasDirty: ObjCBool = false try self.__save(to: url, wasDirty: &wasDirty) return wasDirty.boolValue } } -
31:35 - Fix method names with NS_SWIFT_NAME
// // SKMission.h // // View the generated interface to see how Swift imports this header. // #import <Foundation/Foundation.h> #import <SKAstronaut/SKAstronaut.h> NS_ASSUME_NONNULL_BEGIN @interface SKMission : NSObject - (NSSet<SKMission *> *)previousMissionsFlownByAstronaut:(SKAstronaut *)astronaut NS_SWIFT_NAME(previousMissions(flownBy:)); @end -
33:12 - Rename and rework value types with NS_SWIFT_NAME
// // SKFuelKind.h // // View the generated interface to see how Swift imports this header. // #import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface SKFuel : NSObject // Stub class @end typedef NS_ENUM(NSInteger, SKFuelKind) { SKFuelKindH2 = 0, SKFuelKindCH4 = 1, SKFuelKindC12H26 = 2 } NS_SWIFT_NAME(SKFuel.Kind); NSString *SKFuelKindToNSString(SKFuelKind kind) NS_SWIFT_NAME(getter:SKFuelKind.description(self:)); -
35:59 - Add conformances to Objective-C types using custom Swift code
extension SKFuel.Kind: CustomStringConvertible {} -
37:02 - Improve error code enums
// // SKError.h // SpaceKit // #import <Foundation/Foundation.h> extern NSString *const SKErrorDomain; typedef NS_ERROR_ENUM(SKErrorDomain, SKErrorCode) { SKErrorLaunchAborted = 1, SKErrorLaunchOutOfRange, SKErrorRapidUnscheduledDisassembly, SKErrorNotGoingToSpaceToday };
-