SlideShare a Scribd company logo
1 of 76
Download to read offline
Swift & Objective-C
* “Using Swift with Cocoa and Objective-C” / .
Interoperability
Interacting with Objective-C APIs
- (instancetype)init;
- (instancetype)initWithFrame:(CGRect)frame
style:(UITableViewStyle)style;
init() { /* ... */ }
init(frame: CGRect, style: UITableViewStyle) { /* ... */ }
UITableView *myTableView = [[UITableView alloc] initWithFrame:CGRectZero
style:UITableViewStyleGrouped];
let myTableView: UITableView = UITableView(frame: .zero, style: .grouped)
let myTextField = UITextField(frame: CGRect(x: 0.0, y: 0.0,
width: 200.0, height: 40.0))
Initialization
• Objective-C
• Swift
Interacting with Objective-C APIs
UIColor *color = [UIColor colorWithRed:0.5 green:0.0 blue:0.5 alpha:1.0];
let color = UIColor(red: 0.5, green: 0.0, blue: 0.5, alpha: 1.0)
Convenience Initializers
• Objective-C
• Swift
To be used with the same syntax as initializers.
Interacting with Objective-C APIs
if let image = UIImage(contentsOfFile: "MyImage.png") {
// loaded the image successfully
} else {
// could not load the image
}
Failable Initialization
• Objective-C
• Swift
Initializers directly return the object they initialize. To inform the caller when
initialization has failed, an Objective-C initializer can return nil.
Interacting with Objective-C APIs
Nullability Properties
• Swift
• Objective-C @property (nullable) id nullableProperty;
@property (nonnull) id nonNullProperty;
@property id unannotatedProperty;
NS_ASSUME_NONNULL_BEGIN
- (id)returnsNonNullValue;
- (void)takesNonNullParameter:(id)value;
NS_ASSUME_NONNULL_END
- (nullable id)returnsNullableValue;
- (void)takesNullableParameter:(nullable id)value;
- (id)returnsUnannotatedValue;
- (void)takesUnannotatedParameter:(id)value;
var nullableProperty: Any?
var nonNullProperty: Any
var unannotatedProperty: Any!
func returnsNonNullValue() -> Any
func takesNonNullParameter(value: Any)
func returnsNullableValue() -> Any?
func takesNullableParameter(value: Any?)
func returnsUnannotatedValue() -> Any!
func takesUnannotatedParameter(value: Any!)
Interacting with Objective-C APIs
Accessing Properties
• readonly = computed property { get }
• weak = weak (weak var)
• assign, copy, strong, unsafe_unretained
• Class = Type
• Atomic
• Accessor (getter= / setter=)
Interacting with Objective-C APIs
myTableView.insertSubview(mySubview, at: 2)
Working with Methods
• Objective-C
• Swift
[myTableView insertSubview:mySubview atIndex:2];
myTableView.layoutIfNeeded()
Can call Objective-C methods from Swift using dot syntax.
Interacting with Objective-C APIs
var x: Any = "hello" as String
x as? String // String with value "hello"
x as? NSString // NSString with value "hello"
x = "goodbye" as NSString
x as? String // String with value "goodbye"
x as? NSString // NSString with value "goodbye"
id
• Objective-C
• Swift
The Objective-C id type is imported by Swift as the Any type.
Interacting with Objective-C APIs
let userDefaults = UserDefaults.standard
let lastRefreshDate = userDefaults.object(forKey: "LastRefreshDate")
// lastRefreshDate is of type Any?
if let date = lastRefreshDate as? Date {
print("(date.timeIntervalSinceReferenceDate)")
}
Downcasting Any
let myDate = lastRefreshDate as! Date
let timeInterval = myDate.timeIntervalSinceReferenceDate
let myDate = lastRefreshDate as! String // Error
Forced downcast operator (as!)
Forced downcast error
Conditional type cast operator (as?)
Interacting with Objective-C APIs
var myObject: AnyObject = UITableViewCell()
myObject = NSDate()
let futureDate = myObject.addingTimeInterval(10)
let timeSinceNow = myObject.timeIntervalSinceNow
Dynamic Method Lookup & Optional chaining
AnyObject type lookup @objc method dynamically
myObject.character(at: 5)
// crash, myObject doesn't respond to that method
let myCount = myObject.count
// myCount has Int? type and nil value
let myChar = myObject.character?(at: 5)
// myChar has unichar? type and nil value
if let fifthCharacter = myObject.character?(at: 5) {
print("Found (fifthCharacter) at index 5")
}
// conditional branch not executed
Interacting with Objective-C APIs
Bridging Optionals to Nonnullable Objects
@implementation OptionalBridging
+ (void)logSomeValue:(nonnull id)valueFromSwift {
if ([valueFromSwift isKindOfClass: [NSNull class]]) {
os_log(OS_LOG_DEFAULT, "Received an NSNull value.");
} else {
os_log(OS_LOG_DEFAULT, "%s", [valueFromSwift UTF8String]);
}
}
@end
let someValue: String? = "Bridge me, please."
let nilValue: String? = nil
OptionalBridging.logSomeValue(someValue as Any) // String
OptionalBridging.logSomeValue(nilValue as Any) // an NSNull value.
Optional nil NSNull ,
Optional unwrapped value [T?] => NSArray<T>
Interacting with Objective-C APIs
Lightweight Generics
@property NSArray<NSDate *> *dates;
@property NSCache<NSObject *, id<NSDiscardableContent>> *cachedData;
@property NSDictionary <NSString *, NSArray<NSLocale *>> *supportedLocales;
var dates: [Date]
var cachedData: NSCache<AnyObject, NSDiscardableContent>
var supportedLocales: [String: [Locale]]
• Objective-C
• Swift
Interacting with Objective-C APIs
Generic Class
@interface List<T: id<NSCopying>> : NSObject
- (List<T> *)listByAppendingItemsInList:(List<T> *)otherList;
@end
@interface ListContainer : NSObject
- (List<NSValue *> *)listOfValues;
@end
@interface ListContainer (ObjectList)
- (List *)listOfObjects;
@end
• Objective-C
• Swift class List<T: NSCopying> : NSObject {
func listByAppendingItemsInList(otherList: List<T>) -> List<T>
}
class ListContainer : NSObject {
func listOfValues() -> List<NSValue>
}
extension ListContainer {
func listOfObjects() -> List<NSCopying>
}
Interacting with Objective-C APIs
Extensions (of existing classes, structures…)
extension UIBezierPath {
convenience init(triangleSideLength: CGFloat, origin: CGPoint) {
self.init()
let squareRoot = CGFloat(sqrt(3.0))
let altitude = (squareRoot * triangleSideLength) / 2
move(to: origin)
addLine(to: CGPoint(x: origin.x + triangleSideLength, y: origin.y))
addLine(to: CGPoint(x: origin.x + triangleSideLength / 2, y: origin.y + altitude))
close()
}
}
• Swift
Interacting with Objective-C APIs
Closures & Blocks
void (^completionBlock)(NSData *) = ^(NSData *data) {
// ...
}
• Swift
• Objective-C
let completionBlock: (Data) -> Void = { data in
// ...
}
__weak typeof(self) weakSelf = self;
self.block = ^{
__strong typeof(self) strongSelf = weakSelf;
[strongSelf doSomething];
};
self.closure = { [unowned self] in
self.doSomething()
}
Interacting with Objective-C APIs
Object Comparison
• Swift
• Objective-C
equality : ( -isEqual: )
identity :
equality (==) : (Equatable )
== Operator isEqual:
isEqual:
identity (===) :
=== Operator
Interacting with Objective-C APIs
Hashing
• Swift
• Objective-C
@property NSDictionary *unqualifiedDictionary;
@property NSDictionary<NSString *, NSDate *> *qualifiedDictionary;
@property NSSet *unqualifiedSet;
@property NSSet<NSString *> *qualifiedSet;
var unqualifiedDictionary: [AnyHashable: Any]
var qualifiedDictionary: [String: Date]
var unqualifiedSet: Set<AnyHashable>
var qualifiedSet: Set<String>
Interacting with Objective-C APIs
Excludes Swift-only
• Generics
• Tuples
• Enumerations defined in Swift without Int raw value type
• Structures defined in Swift
• Top-level functions defined in Swift
• Global variables defined in Swift
• Typealiases defined in Swift
• Swift-style variadics
• Nested types
• Curried functions
Interacting with Objective-C APIs
Swift Type Compatibility
class Jukebox: NSObject {
var library: Set<String>
var nowPlaying: String?
var isCurrentlyPlaying: Bool {
return nowPlaying != nil
}
class var favoritesPlaylist: [String] {
// return an array of song names
}
init(songs: String...) {
self.library = Set<String>(songs)
}
func playSong(named name: String) throws {
// play song or throw an error if unavailable
}
}
@interface Jukebox : NSObject
@property (nonatomic, strong, nonnull) NSSet<NSString *> *library;
@property (nonatomic, copy, nullable) NSString *nowPlaying;
@property (nonatomic, readonly, getter=isCurrentlyPlaying) BOOL currentlyPlaying;
@property (nonatomic, class, readonly, nonnull) NSArray<NSString *> * favoritesPlaylist;
- (nonnull instancetype)initWithSongs:(NSArray<NSString *> * __nonnull)songs
OBJC_DESIGNATED_INITIALIZER;
- (BOOL)playSong:(NSString * __nonnull)name
error:(NSError * __nullable * __null_unspecified)error;
@end
Interacting with Objective-C APIs
Configuring Swift Interfaces
@objc(Color)
enum Цвет: Int {
@objc(Red)
case Красный
@objc(Black)
case Черный
}
@objc(Squirrel)
class Белка: NSObject {
@objc(color)
var цвет: Цвет = .Красный
@objc(initWithName:)
init (имя: String) {
// ...
}
@objc(hideNuts:inTree:)
func прячьОрехи(количество: Int, вДереве дерево: Дерево) {
// ...
}
}
Interacting with Objective-C APIs
Selectors
import UIKit
class MyViewController: UIViewController {
let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
override init?(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
let action = #selector(MyViewController.tappedButton)
myButton.addTarget(self, action: action, forControlEvents: .touchUpInside)
}
func tappedButton(sender: UIButton?) {
print("tapped button")
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
Interacting with Objective-C APIs
Unsafe Invocation of Objective-C Methods
let string: NSString = "Hello, Cocoa!"
let selector = #selector(NSString.lowercased(with:))
let locale = Locale.current
if let result = string.perform(selector, with: locale) {
print(result.takeUnretainedValue())
}
// Prints "hello, cocoa!"
let array: NSArray = ["delta", "alpha", "zulu"]
// Not a compile-time error because NSDictionary has this selector.
let selector = #selector(NSDictionary.allKeysForObject)
// Raises an exception because NSArray does not respond to this selector.
array.perform(selector)
Perform Selector
Unsafe invocation
Interacting with Objective-C APIs
Keys & Key Paths
class Person: NSObject {
var name: String
var friends: [Person] = []
var bestFriend: Person? = nil
init(name: String) {
self.name = name
}
}
let gabrielle = Person(name: "Gabrielle")
let jim = Person(name: "Jim")
let yuanyuan = Person(name: "Yuanyuan")
gabrielle.friends = [jim, yuanyuan]
gabrielle.bestFriend = yuanyuan
#keyPath(Person.name)
// "name"
gabrielle.value(forKey: #keyPath(Person.name))
// "Gabrielle"
#keyPath(Person.bestFriend.name)
// "bestFriend.name"
gabrielle.value(forKeyPath: #keyPath(Person.bestFriend.name))
// "Yuanyuan"
#keyPath(Person.friends.name)
// "friends.name"
gabrielle.value(forKeyPath: #keyPath(Person.friends.name))
// ["Yuanyuan", "Jim"]
Objective-C Behavior
Inheriting from Objective-C Classes
@IBDesignable, @IBInpectable
let myPersonClass: AnyClass? = NSClassFromString("MyGreatApp.Person")
Working with Cocoa Frameworks
Foundation
Working with Cocoa Frameworks
Core Foundation
CFStringRef StringByAddingTwoStrings(CFStringRef s1, CFStringRef s2)
func StringByAddingTwoStrings(_: CFString!, _: CFString!) -> Unmanaged<CFString>! {
// ...
}
let memoryManagedResult = StringByAddingTwoStrings(str1, str2).takeUnretainedValue()
CFTypeRef remaps to the AnyObject
CFStringRef remaps to the CFString class
takeRetainedValue()
Working with Cocoa Frameworks
Unified Logging
import os.log
os_log("This is a log message.”)
let fileSize = 1234567890
os_log("Finished downloading file. Size: %{iec-bytes}d", fileSize)
os_log("This is additional info that may be helpful for troubleshooting.", type: .info)
let customLog = OSLog("com.your_company.your_subsystem_name.plist", "your_category_name")
os_log("This is info that may be helpful during development or debugging.",
log: customLog, type: .debug)
Working with Cocoa Frameworks
Cocoa structure
NSValue
MKCoordinateSpan
NSRange
CLLocationCoordinate2D
CATransform3D, CGAffineTransform
CGPoint, CGRect, CGSize, CGVector
CMTimeMapping, CMTimeRange, CMTime
SCNMatrix4, SCNVector3, SCNVector4
UIEdgeInsets, UIOffset
NSValue
Adopting Cocoa Design Patterns
Delegation
1)Check that myDelegate is not nil.
2)Check that myDelegate implements the method
window:willUseFullScreenContentSize:.
3)If 1 and 2 hold true, invoke the method and assign the result of the method
to the value named fullScreenSize.
4)Print the return value of the method.
class MyDelegate: NSObject, NSWindowDelegate {
func window(_ window: NSWindow, willUseFullScreenContentSize proposedSize: NSSize) -> NSSize {
return proposedSize
}
}
//…
myWindow.delegate = MyDelegate()
if let fullScreenSize = myWindow.delegate?.window(myWindow, willUseFullScreenContentSize: mySize) {
print(NSStringFromSize(fullScreenSize))
}
Adopting Cocoa Design Patterns
Lazy Initialization
@property NSXMLDocument *XML;
- (NSXMLDocument *)XML {
if (_XML == nil) {
_XML = [[NSXMLDocument alloc] initWithContentsOfURL:[[Bundle mainBundle]
URLForResource:@"/path/to/resource" withExtension:@"xml"] options:0 error:nil];
}
return _XML;
}
lazy var XML: XMLDocument = try! XMLDocument(contentsOf:
Bundle.main.url(forResource: "document", withExtension: "xml")!, options: 0)
• Objective-C
• Swift
Adopting Cocoa Design Patterns
Lazy property
var pattern: String
lazy var regex: NSRegularExpression = try! NSRegularExpression(pattern: self.pattern,
options: [])
lazy var currencyFormatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencySymbol = "¤"
return formatter
}()
• Swift
use self-evaluating closure
Adopting Cocoa Design Patterns
Error Handling
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *fromURL = [NSURL fileURLWithPath:@"/path/to/old"];
NSURL *toURL = [NSURL fileURLWithPath:@"/path/to/new"];
NSError *error = nil;
BOOL success = [fileManager moveItemAtURL:fromURL toURL:toURL error:&error];
if (!success) {
NSLog(@"Error: %@", error.domain);
}
• Swift
• Objective-C
let fileManager = FileManager.default
let fromURL = URL(fileURLWithPath: "/path/to/old")
let toURL = URL(fileURLWithPath: "/path/to/new")
do {
try fileManager.moveItem(at: fromURL, to: toURL)
} catch let error as NSError {
print("Error: (error.domain)")
}
Adopting Cocoa Design Patterns
Converting errors to Optional values
• Swift
• Objective-C
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *tmpURL = [fileManager URLForDirectory:NSCachesDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:YES
error:nil];
if (tmpURL != nil) {
// ...
}
let fileManager = FileManager.default
if let tmpURL = try? fileManager.url(for: .cachesDirectory, in: .userDomainMask,
appropriateFor: nil, create: true) {
// ...
}
Adopting Cocoa Design Patterns
Throwing error
• Swift
• Objective-C
// an error occurred
if (errorPtr) {
*errorPtr = [NSError errorWithDomain:NSURLErrorDomain
code:NSURLErrorCannotOpenFile
userInfo:nil];
}
// an error occurred
throw NSError(domain: NSURLErrorDomain, code: NSURLErrorCannotOpenFile, userInfo: nil)
Adopting Cocoa Design Patterns
Key-value Observing
KVO with a Swift class inherits from NSObject class
1) Add dynamic modifier to any property
2) Create a global context variable
3) Add an observer for the key-path, override the observeValue() method
and remove the observer in deinit.
class MyObjectToObserve: NSObject {
dynamic var myDate = NSDate()
func updateDate() {
myDate = NSDate()
}
}
private var myContext = 0
class MyObserver: NSObject {
var objectToObserve = MyObjectToObserve()
override init() {
super.init()
objectToObserve.addObserver(self, forKeyPath: #keyPath(MyObjectToObserve.myDate),
options: .new, context: &myContext)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change:
[NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &myContext {
if let newValue = change?[.newKey] { print("Date changed: (newValue)”) }
} else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}
deinit {
objectToObserve.removeObserver(self, forKeyPath: #keyPath(MyObjectToObserve.myDate),
context: &myContext)
}
}
Adopting Cocoa Design Patterns
Undo architecture
Create an undo operation using an NSInvocation
@IBOutlet var remainingLabel: NSTextView!
func mark(task: Task, asCompleted completed: Bool) {
if let target = undoManager?.prepare(withInvocationTarget: self) as? ToDoListController {
target.mark(task: task, asCompleted: !completed)
undoManager?.setActionName(NSLocalizedString("todo.task.mark",
comment: "Mark As Completed"))
}
task.completed = completed
tableView.reloadData()
let numberRemaining = tasks.filter{ $0.completed }.count
remainingLabel.string = String(format: NSLocalizedString("todo.task.remaining",
comment: "Tasks Remaining: %d"), numberRemaining)
}
Adopting Cocoa Design Patterns
Singleton
initialization in a call the dispatch_once function
+ (instancetype)sharedInstance {
static id _sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedInstance = [[self alloc] init];
});
return _sharedInstance;
}
class Singleton {
static let sharedInstance = Singleton()
}
class Singleton {
static let sharedInstance: Singleton = {
let instance = Singleton()
// setup code
return instance
}()
}
Adopting Cocoa Design Patterns
Introspection
use the isKindOfClass: method or conformsToProtocol: method
if object is UIButton {
// object is of type UIButton
} else {
// object is not of type UIButton
}
if let button = object as? UIButton {
// object is successfully cast to type UIButton and bound to button
} else {
// object could not be cast to type UIButton
}
if let dataSource = object as? UITableViewDataSource {
// object conforms to UITableViewDataSource and is bound to dataSource
} else {
// object not conform to UITableViewDataSource
}
• Swift
• Objective-C
Adopting Cocoa Design Patterns
Serialization
To encode and decode objects to and from architecture-independent representations.
Use NSJSONSerialization and NSPropertyListSerialization
import Foundation
import CoreLocation
struct Venue {
enum Category: String {
case entertainment
case food
case nightlife
case shopping
}
var name: String
var coordinates: CLLocationCoordinate2D
var category: Category
}
{
"name": "Caffè Macs",
"coordinates": {
"lat": 37.330576,
"lng": -122.029739
},
"category": "food"
}
Adopting Cocoa Design Patterns
Serialization : Initializer
init?(attributes: [String: Any]) {
guard let name = attributes["name"] as? String,
let coordinates = attributes["coordinates"] as? [String: Double],
let latitude = coordinates["lat"],
let longitude = coordinates["lng"],
let category = Category(rawValue: attributes["category"] as? String ?? "Invalid")
else {
return nil
}
self.name = name
self.coordinates = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
self.category = category
}
let JSON = "{"name": "Caffè Macs","coordinates": {"lat": 37.330576,"lng": -122.029739},
"category": "food"}"
let data = JSON.data(using: String.Encoding.utf8)!
let attributes = try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
let venue = Venue(attributes: attributes)!
print(venue.name)
// Prints "Caffè Macs"
Initialize with Dictionary<String, Any>
Create a Venue from a JSON representation
Adopting Cocoa Design Patterns
Serialization : Validating
enum ValidationError: Error {
case missing(String)
case invalid(String)
}
init(attributes: [String: Any]) throws {
guard let name = attributes["name"] as? String else {
throw ValidationError.missing("name")
}
guard let coordinates = attributes["coordinates"] as? [String: Double] else {
throw ValidationError.missing("coordinates")
}
guard let latitude = coordinates["lat"],
let longitude = coordinates["lng"]
else {
throw ValidationError.invalid("coordinates")
}
guard let categoryName = attributes["category"] as? String else {
throw ValidationError.missing("category")
}
guard let category = Category(rawValue: categoryName) else {
throw ValidationError.invalid("category")
}
self.name = name
self.coordinates = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
self.category = category
}
Adopting Cocoa Design Patterns
Localization
use NSLocalizedString, NSLocalizedStringFromTable,
NSLocalizedStringFromTableInBundle, NSLocalizedStringWithDefaultValue
• Objective-C
• Swift
A single function: NSLocalizedString(_:tableName:bundle:value:comment:)
let format = NSLocalizedString("Hello, %@!", comment: "Hello, {given name}!")
let name = "Mei"
let greeting = String(format: format, arguments: [name as CVarArg])
print(greeting)
// Prints "Hello, Mei!"
if let path = Bundle.main.path(forResource: "Localization", ofType: "strings",
inDirectory: nil, forLocalization: "ja"),
let bundle = Bundle(path: path) {
let translation = NSLocalizedString("Hello", bundle: bundle, comment: "")
print(translation)
}
// Prints " "
Adopting Cocoa Design Patterns
API Availability
use respondsToSelector: and instancesRespondToSelector: methods
• Objective-C
• Swift
let locationManager = CLLocationManager()
if #available(iOS 8.0, macOS 10.10, *) {
locationManager.requestWhenInUseAuthorization()
}
if ([CLLocationManager instancesRespondToSelector:@selector(requestWhenInUseAuthorization)]) {
// Method is available for use.
} else {
// Method is not available.
}
let locationManager = CLLocationManager()
guard #available(iOS 8.0, macOS 10.10, *) else { return }
locationManager.requestWhenInUseAuthorization()
Adopting Cocoa Design Patterns
Processing Command-Line Arguments
for argument in CommandLine.arguments {
print(argument)
}
// prints "/path/to/app"
// prints "--argumentName"
// prints "value"
$ /path/to/app --argumentName value
Interacting with C APIs
Primitive Types
C Type Swift Type
bool CBool
char, signed char CChar
unsigned char CUnsignedChar
short CShort
unsigned short CUnsignedShort
int CInt
unsigned int CUnsignedInt
long CLong
unsigned long CUnsignedLong
long long CLongLong
unsigned long long CUnsignedLongLong
wchar_t CWideChar
char16_t CChar16
char32_t CChar32
float CFloat
double CDouble
Interacting with C APIs
Importing Constant Enumerations and Structures
Annotate an typedef declaration with the NS_STRING_ENUM or
NS_EXTENSIBLE_STRING_ENUM
• Objective-C
• Swift
struct TrafficLightColor: RawRepresentable {
typealias RawValue = String
init(rawValue: RawValue)
var rawValue: RawValue { get }
static var red: TrafficLightColor { get }
static var yellow: TrafficLightColor { get }
static var green: TrafficLightColor { get }
}
typedef NSString * TrafficLightColor NS_STRING_ENUM;
TrafficLightColor const TrafficLightColorRed;
TrafficLightColor const TrafficLightColorYellow;
TrafficLightColor const TrafficLightColorGreen;
Interacting with C APIs
Functions
Any function declared in a C header as a Swift global function.
• Objective-C
• Swift
func product(_ multiplier: Int32, _ multiplicand: Int32) -> Int32
func quotient(_ dividend: Int32, _ divisor: Int32, _ remainder:
UnsafeMutablePointer<Int32>) -> Int32
func createPoint2D(_ x: Float, _ y: Float) -> Point2D
func distance(_ from: Point2D, _ to: Point2D) -> Float
int product(int multiplier, int multiplicand);
int quotient(int dividend, int divisor, int *remainder);
struct Point2D createPoint2D(float x, float y);
float distance(struct Point2D from, struct Point2D to);
Interacting with C APIs
Variadic Functions
Call C variadic functions, such as vasprintf, using the getVaList() or withVaList()
func swiftprintf(format: String, arguments: CVarArg...) -> String? {
return withVaList(arguments) { va_list in
var buffer: UnsafeMutablePointer<Int8>? = nil
return format.withCString { CString in
guard vasprintf(&buffer, CString, va_list) != 0 else {
return nil
}
return String(validatingUTF8: buffer!)
}
}
}
print(swiftprintf(format: "√2 ≅ %g", arguments: sqrt(2.0))!)
// Prints "√2 ≅ 1.41421"
Interacting with C APIs
Structures
Any C Structure declared in a C header as a Swift structure.
struct Color {
float r, g, b;
};
typedef struct Color Color;
public struct Color {
var r: Float
var g: Float
var b: Float
init()
init(r: Float, g: Float, b: Float)
}
• Swift
Interacting with C APIs
Importing Functions as Type Members
Use CF_SWIFT_NAME macro in you own code
Color ColorCreateWithCMYK(float c, float m, float y, float k) CF_SWIFT_NAME(Color.init(c:m:y:k:));
float ColorGetHue(Color color) CF_SWIFT_NAME(getter:Color.hue(self:));
void ColorSetHue(Color color, float hue) CF_SWIFT_NAME(setter:Color.hue(self:newValue:));
Color ColorDarkenColor(Color color, float amount) CF_SWIFT_NAME(Color.darken(self:amount:));
extern const Color ColorBondiBlue CF_SWIFT_NAME(Color.bondiBlue);
Color ColorGetCalibrationColor(void) CF_SWIFT_NAME(getter:Color.calibration());
Color ColorSetCalibrationColor(Color color) CF_SWIFT_NAME(setter:Color.calibration(newValue:));
extension Color {
init(c: Float, m: Float, y: Float, k: Float)
var hue: Float { get set }
func darken(amount: Float) -> Color
static var bondiBlue: Color
static var calibration: Color
}
• Swift
Interacting with C APIs
Enumerations
Any C enumeration marked with the NS_ENUM macro as a Swift Enumeration(Int)
typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
UITableViewCellStyleDefault,
UITableViewCellStyleValue1,
UITableViewCellStyleValue2,
UITableViewCellStyleSubtitle
};
enum UITableViewCellStyle: Int {
case `default`
case value1
case value2
case subtitle
}
• Swift
let cellStyle: UITableViewCellStyle = .default
Interacting with C APIs
Enumerations : Option Sets
Any C enumeration marked with the NS_OPTIONS macro as a Swift option set.
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
public struct UIViewAutoresizing : OptionSet {
public init(rawValue: UInt)
public static var flexibleLeftMargin: UIViewAutoresizing { get }
public static var flexibleWidth: UIViewAutoresizing { get }
public static var flexibleRightMargin: UIViewAutoresizing { get }
public static var flexibleTopMargin: UIViewAutoresizing { get }
public static var flexibleHeight: UIViewAutoresizing { get }
public static var flexibleBottomMargin: UIViewAutoresizing { get }
}
• Swift
Interacting with C APIs
Unions
Swift imports C unions as Swift structures, not support unions.
union SchroedingersCat {
bool isAlive;
bool isDead;
};
struct SchroedingersCat {
var isAlive: Bool { get set }
var isDead: Bool { get set }
init(isAlive: Bool)
init(isDead: Bool)
init()
}
• Swift
Interacting with C APIs
Unnamed Structure and Union Fields
C struct and union types can define fields that have no name or that are of an
unnamed type.
struct Cake {
union {
int layers;
double height;
};
struct {
bool icing;
bool sprinkles;
} toppings;
};
var simpleCake = Cake()
simpleCake.layers = 5
print(simpleCake.toppings.icing)
// Prints "false"
let cake = Cake(
.init(layers: 2),
toppings: .init(icing: true, sprinkles: false)
)
print("The cake has (cake.layers) layers.")
// Prints "The cake has 2 layers."
print("Does it have sprinkles?", cake.toppings.sprinkles ? "Yes." : "No.")
// Prints "Does it have sprinkles? No."
Interacting with C APIs
Pointers
C Syntax Swift Syntax
const Type * UnsafePointer<Type>
Type * UnsafeMutablePointer<Type>
C Syntax Swift Syntax
Type * const * UnsafePointer<Type>
Type * __strong * UnsafeMutablePointer<Type>
Type ** AutoreleasingUnsafeMutablePointer<Type>
C Syntax Swift Syntax
const void * UnsafePointer
void * UnsafeMutablePointer
For return types, variables, and arguments
For class types
For pointers to untyped, raw memory
Interacting with C APIs
Constant Pointers
func takesAPointer(_ p: UnsafePointer<Float>) {
// ...
}
var x: Float = 0.0
takesAPointer(&x)
takesAPointer([1.0, 2.0, 3.0])
var x: Float = 0.0, y: Int = 0
takesARawPointer(&x)
takesARawPointer(&y)
takesARawPointer([1.0, 2.0, 3.0] as [Float])
let intArray = [1, 2, 3]
takesARawPointer(intArray)
func takesARawPointer(_ p: UnsafeRawPointer?) {
// ...
}
Interacting with C APIs
Mutable Pointers
func takesAMutablePointer(_ p: UnsafeMutablePointer<Float>) {
// ...
}
var x: Float = 0.0
var a: [Float] = [1.0, 2.0, 3.0]
takesAMutablePointer(&x)
takesAMutablePointer(&a)
var x: Float = 0.0, y: Int = 0
var a: [Float] = [1.0, 2.0, 3.0], b: [Int] = [1, 2, 3]
takesAMutableRawPointer(&x)
takesAMutableRawPointer(&y)
takesAMutableRawPointer(&a)
takesAMutableRawPointer(&b)
func takesAMutableRawPointer(_ p: UnsafeMutableRawPointer?) {
// ...
}
Interacting with C APIs
Autoreleasing Pointers
func takesAnAutoreleasingPointer(_ p: AutoreleasingUnsafeMutablePointer<NSDate?>) {
// ...
}
var x: NSDate? = nil
takesAnAutoreleasingPointer(&x)
Interacting with C APIs
Function Pointers
func customCopyDescription(_ p: UnsafeRawPointer?) -> Unmanaged<CFString>? {
// return an Unmanaged<CFString>? value
}
var callbacks = CFArrayCallBacks(
version: 0,
retain: nil,
release: nil,
copyDescription: customCopyDescription,
equal: { (p1, p2) -> DarwinBoolean in
// return Bool value
}
)
var mutableArray = CFArrayCreateMutable(nil, 0, &callbacks)
C function pointers are imported into Swift as closures with C function pointer calling
convention, denoted by the @convention(c) attribute.
Interacting with C APIs
Buffer Pointers & Null Pointers
Buffer Pointers : Used for low-level access to a region of memory.
UnsafeBufferPointer
UnsafeMutableBufferPointer
UnsafeRawBufferPointer
UnsafeMutableRawBufferPointer
Objective-C Syntax Swift Syntax
const Type * _Nonnull UnsafePointer<Type>
const Type * _Nullable UnsafePointer<Type>?
const Type * _Null_unspecified UnsafePointer<Type>!
Null Pointers
Pointers Arithmatic
let pointer: UnsafePointer<Int8>
let offsetPointer = pointer + 24
// offsetPointer is 24 strides ahead of pointer
Interacting with C APIs
Data Type Size Calculation
In C, the sizeof and alignof operators return the size and alignment
In Swift, you use MemoryLayout<T> to access the memory layout of the
parameterized type T through the size, stride, and alignment properties.
print(MemoryLayout<timeval>.size)
// Prints "16"
print(MemoryLayout<timeval>.stride)
// Prints "16"
print(MemoryLayout<timeval>.alignment)
// Prints "8"
let sockfd = socket(AF_INET, SOCK_STREAM, 0)
var optval = timeval(tv_sec: 30, tv_usec: 0)
let optlen = socklen_t(MemoryLayout<timeval>.size)
if setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &optval, optlen) == 0 {
// ...
}
Interacting with C APIs
Preprocessor Directives
Simple Macro
Complex Macro, no counterpart in Swift
Conditional Compilation Blocks
#if DEBUG_LOGGING
print("Flag enabled.")
#endif
#define FADE_ANIMATION_DURATION 0.35 let FADE_ANIMATION_DURATION = 0.35
Function Valid arguments
os() macOS, iOS, watchOS, tvOS, Linux
arch() x86_64, arm, arm64, i386
swift() >= followed by a version number
#if arch(arm) || arch(arm64)
#if swift(>=3.0)
print("Using Swift 3 ARM code")
#else
print("Using Swift 2.2 ARM code")
#endif
#elseif arch(x86_64)
print("Using 64-bit x86 code.")
#else
print("Using general code.")
#endif
Mix & Match
Mix and Match Overview
Swift & Objective-C in the Same Project
Importing Objective-C into Swift
rely on an Objective-C bridging header to expose those files to Swift
{product module name} + "-Bridging-Header.h"
ex. = CodesquadApp CodesquadApp-Bridging-Header.h
To import Objective-C code into Swift from the same target
1) In your Objective-C bridging header file, import every Objective-C header
2) In Build Settings > Swift Compiler - Code Generation, make sure the Objective-C
Bridging Header build setting has a path to the bridging header file
Swift & Objective-C in the Same Project
Importing Swift into Objective-C
rely on an Xcode-generated header file to expose those files to Objective-C
{product module name} + "-Swift.h"
ex. = CodesquadApp CodesquadApp-Swift.h
The generated header contains interfaces for Swift declarations marked with the
public or open modifier.
An umbrella header for your Swift code
Marked with the internal modifier if your app target has bridging header.
To import Swift code into Objective-C from the same target
#import "ProductModuleName-Swift.h"
Swift & Objective-C in the Same Project
Importing External Frameworks
Swift code
import FrameworkName @import FrameworkName;
Objective-C code
Import into Swift Import into Objective-C
Any language
framework
import FrameworkName @import FrameworkName;
Swift & Objective-C in the Same Project
Using Swift from Objective-C
Swift class
MySwiftClass *swiftObject = [[MySwiftClass alloc] init];
[swiftObject swiftMethod];
// MyObjcClass.h
@class MySwiftClass;
@protocol MySwiftProtocol;
@interface MyObjcClass : NSObject
- (MySwiftClass *)returnSwiftClassInstance;
- (id <MySwiftProtocol>)returnInstanceAdoptingSwiftProtocol;
// ...
@end
Referencing a Swift Class or Protocol in an Objective-C Header
Swift & Objective-C in the Same Project
Using Swift from Objective-C
Declaring a Swift Protocol That Can Be Adopted by an Objective-C Class
@objc public protocol MySwiftProtocol {
func requiredMethod()
@objc optional func optionalMethod()
}
// MyObjcClass.m
#import "ProductModuleName-Swift.h"
@interface MyObjcClass () <MySwiftProtocol>
// ...
@end
@implementation MyObjcClass
// ...
@end
Adopting a Swift Protocol in an Objective-C Implementation
Swift & Objective-C in the Same Project
Using Swift from Objective-C
Declaring a Swift Error Type That Can Be Used from Objective-C
@objc public enum CustomError: Int, Error {
case a, b, c
}
// Project-Swift.h
typedef SWIFT_ENUM(NSInteger, CustomError) {
CustomErrorA = 0,
CustomErrorB = 1,
CustomErrorC = 2,
};
static NSString * const CustomErrorDomain = @"Project.CustomError";
In generated header:
Swift & Objective-C in the Same Project
Overriding Swift Names for Objective-C Interfaces
Class Factory Methods
+ (instancetype)recordWithRPM:(NSUInteger)RPM NS_SWIFT_NAME(init(rpm:));
+ (id)recordWithQuality:(double)quality NS_SWIFT_NAME(record(quality:));
typedef NS_ENUM(NSInteger, ABCRecordSide) {
ABCRecordSideA,
ABCRecordSideB NS_SWIFT_NAME(flipSide),
};
Enumerations
Swift compiler automatically imports Objective-C code as conventional Swift code.
Swift & Objective-C in the Same Project
Making Objective-C Interfaces Unavailable in Swift
Convenience Initializer
+ (instancetype)collectionWithValues:(NSArray *)values forKeys:
(NSArray<NSCopying> *)keys NS_SWIFT_UNAVAILABLE("Use a dictionary literal
instead");
Some Objective-C interfaces may not be suitable or necessary to be exposed as Swift
Objective-C class providing a convenience initializer that takes variadic arguments for keys-value
pairs may advise a Swift consumer to use a dictionary literal instead:
Swift & Objective-C in the Same Project
Refining Objective-C Declarations
use the NS_REFINED_FOR_SWIFT macro on an Objective-C method declaration to
provide a refined Swift interface in an extension
@interface Color : NSObject
- (void)getRed:(nullable CGFloat *)red
green:(nullable CGFloat *)green
blue:(nullable CGFloat *)blue
alpha:(nullable CGFloat *)alpha NS_REFINED_FOR_SWIFT;
@end
extension Color {
var RGBA: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
var r: CGFloat = 0.0
var g: CGFloat = 0.0
var b: CGFloat = 0.0
var a: CGFloat = 0.0
__getRed(red: &r, green: &g, blue: &b, alpha: &a)
return (red: r, green: g, blue: b, alpha: a)
}
}
Swift & Objective-C in the Same Project
Troubleshooting Tips and Reminders

More Related Content

What's hot

ES6 - Next Generation Javascript
ES6 - Next Generation JavascriptES6 - Next Generation Javascript
ES6 - Next Generation JavascriptRamesh Nair
 
Introduction to Ecmascript - ES6
Introduction to Ecmascript - ES6Introduction to Ecmascript - ES6
Introduction to Ecmascript - ES6Nilesh Jayanandana
 
Mastering Kotlin Standard Library
Mastering Kotlin Standard LibraryMastering Kotlin Standard Library
Mastering Kotlin Standard LibraryNelson Glauber Leal
 
From android/java to swift (3)
From android/java to swift (3)From android/java to swift (3)
From android/java to swift (3)allanh0526
 
Objective-Cひとめぐり
Objective-CひとめぐりObjective-Cひとめぐり
Objective-CひとめぐりKenji Kinukawa
 
Objective-C for Java Developers
Objective-C for Java DevelopersObjective-C for Java Developers
Objective-C for Java DevelopersBob McCune
 
Swift, functional programming, and the future of Objective-C
Swift, functional programming, and the future of Objective-CSwift, functional programming, and the future of Objective-C
Swift, functional programming, and the future of Objective-CAlexis Gallagher
 
JavaScript Web Development
JavaScript Web DevelopmentJavaScript Web Development
JavaScript Web Developmentvito jeng
 
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵Wanbok Choi
 
AST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptAST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptIngvar Stepanyan
 
Objective-C Crash Course for Web Developers
Objective-C Crash Course for Web DevelopersObjective-C Crash Course for Web Developers
Objective-C Crash Course for Web DevelopersJoris Verbogt
 
Type Driven Development with TypeScript
Type Driven Development with TypeScriptType Driven Development with TypeScript
Type Driven Development with TypeScriptGarth Gilmour
 
Introduction to Scala for Java Developers
Introduction to Scala for Java DevelopersIntroduction to Scala for Java Developers
Introduction to Scala for Java DevelopersMichael Galpin
 
Explaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to ComeExplaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to ComeCory Forsyth
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016Manoj Kumar
 
Aplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & JetpackAplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & JetpackNelson Glauber Leal
 
EcmaScript 6 - The future is here
EcmaScript 6 - The future is hereEcmaScript 6 - The future is here
EcmaScript 6 - The future is hereSebastiano Armeli
 
Javascript Uncommon Programming
Javascript Uncommon ProgrammingJavascript Uncommon Programming
Javascript Uncommon Programmingjeffz
 
A Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsA Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsMichael Pirnat
 

What's hot (20)

ES6 - Next Generation Javascript
ES6 - Next Generation JavascriptES6 - Next Generation Javascript
ES6 - Next Generation Javascript
 
Introduction to Ecmascript - ES6
Introduction to Ecmascript - ES6Introduction to Ecmascript - ES6
Introduction to Ecmascript - ES6
 
Mastering Kotlin Standard Library
Mastering Kotlin Standard LibraryMastering Kotlin Standard Library
Mastering Kotlin Standard Library
 
From android/java to swift (3)
From android/java to swift (3)From android/java to swift (3)
From android/java to swift (3)
 
Objective-Cひとめぐり
Objective-CひとめぐりObjective-Cひとめぐり
Objective-Cひとめぐり
 
Objective-C for Java Developers
Objective-C for Java DevelopersObjective-C for Java Developers
Objective-C for Java Developers
 
Swift, functional programming, and the future of Objective-C
Swift, functional programming, and the future of Objective-CSwift, functional programming, and the future of Objective-C
Swift, functional programming, and the future of Objective-C
 
JavaScript Web Development
JavaScript Web DevelopmentJavaScript Web Development
JavaScript Web Development
 
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
 
AST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptAST - the only true tool for building JavaScript
AST - the only true tool for building JavaScript
 
Objective-C Crash Course for Web Developers
Objective-C Crash Course for Web DevelopersObjective-C Crash Course for Web Developers
Objective-C Crash Course for Web Developers
 
Type Driven Development with TypeScript
Type Driven Development with TypeScriptType Driven Development with TypeScript
Type Driven Development with TypeScript
 
Introduction to Scala for Java Developers
Introduction to Scala for Java DevelopersIntroduction to Scala for Java Developers
Introduction to Scala for Java Developers
 
Explaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to ComeExplaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to Come
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016
 
Aplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & JetpackAplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & Jetpack
 
EcmaScript 6 - The future is here
EcmaScript 6 - The future is hereEcmaScript 6 - The future is here
EcmaScript 6 - The future is here
 
ES6 Overview
ES6 OverviewES6 Overview
ES6 Overview
 
Javascript Uncommon Programming
Javascript Uncommon ProgrammingJavascript Uncommon Programming
Javascript Uncommon Programming
 
A Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsA Few of My Favorite (Python) Things
A Few of My Favorite (Python) Things
 

Similar to Swift와 Objective-C를 함께 쓰는 방법

Working with Cocoa and Objective-C
Working with Cocoa and Objective-CWorking with Cocoa and Objective-C
Working with Cocoa and Objective-CKazunobu Tasaka
 
Real World Generics In Swift
Real World Generics In SwiftReal World Generics In Swift
Real World Generics In SwiftVadym Markov
 
Scaladroids: Developing Android Apps with Scala
Scaladroids: Developing Android Apps with ScalaScaladroids: Developing Android Apps with Scala
Scaladroids: Developing Android Apps with ScalaOstap Andrusiv
 
Agile Iphone Development
Agile Iphone DevelopmentAgile Iphone Development
Agile Iphone DevelopmentGiordano Scalzo
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기Arawn Park
 
Modernizes your objective C - Oliviero
Modernizes your objective C - OlivieroModernizes your objective C - Oliviero
Modernizes your objective C - OlivieroCodemotion
 
Denis Lebedev, Swift
Denis  Lebedev, SwiftDenis  Lebedev, Swift
Denis Lebedev, SwiftYandex
 
TypeScript Best Practices
TypeScript Best PracticesTypeScript Best Practices
TypeScript Best Practicesfelixbillon
 
Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)HamletDRC
 
Cocoa for Web Developers
Cocoa for Web DevelopersCocoa for Web Developers
Cocoa for Web Developersgeorgebrock
 
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with EclipseEclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with EclipseHeiko Behrens
 
AST Transformations
AST TransformationsAST Transformations
AST TransformationsHamletDRC
 
JavaScript and the AST
JavaScript and the ASTJavaScript and the AST
JavaScript and the ASTJarrod Overson
 
ITT 2015 - Saul Mora - Object Oriented Function Programming
ITT 2015 - Saul Mora - Object Oriented Function ProgrammingITT 2015 - Saul Mora - Object Oriented Function Programming
ITT 2015 - Saul Mora - Object Oriented Function ProgrammingIstanbul Tech Talks
 
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KZepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KThomas Fuchs
 

Similar to Swift와 Objective-C를 함께 쓰는 방법 (20)

Working with Cocoa and Objective-C
Working with Cocoa and Objective-CWorking with Cocoa and Objective-C
Working with Cocoa and Objective-C
 
Real World Generics In Swift
Real World Generics In SwiftReal World Generics In Swift
Real World Generics In Swift
 
Scaladroids: Developing Android Apps with Scala
Scaladroids: Developing Android Apps with ScalaScaladroids: Developing Android Apps with Scala
Scaladroids: Developing Android Apps with Scala
 
Agile Iphone Development
Agile Iphone DevelopmentAgile Iphone Development
Agile Iphone Development
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
 
Modernizes your objective C - Oliviero
Modernizes your objective C - OlivieroModernizes your objective C - Oliviero
Modernizes your objective C - Oliviero
 
Day 1
Day 1Day 1
Day 1
 
Play á la Rails
Play á la RailsPlay á la Rails
Play á la Rails
 
Denis Lebedev, Swift
Denis  Lebedev, SwiftDenis  Lebedev, Swift
Denis Lebedev, Swift
 
Runtime
RuntimeRuntime
Runtime
 
TypeScript Best Practices
TypeScript Best PracticesTypeScript Best Practices
TypeScript Best Practices
 
iOS Session-2
iOS Session-2iOS Session-2
iOS Session-2
 
Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)
 
Cocoa for Web Developers
Cocoa for Web DevelopersCocoa for Web Developers
Cocoa for Web Developers
 
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with EclipseEclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
 
360|iDev
360|iDev360|iDev
360|iDev
 
AST Transformations
AST TransformationsAST Transformations
AST Transformations
 
JavaScript and the AST
JavaScript and the ASTJavaScript and the AST
JavaScript and the AST
 
ITT 2015 - Saul Mora - Object Oriented Function Programming
ITT 2015 - Saul Mora - Object Oriented Function ProgrammingITT 2015 - Saul Mora - Object Oriented Function Programming
ITT 2015 - Saul Mora - Object Oriented Function Programming
 
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KZepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
 

More from Jung Kim

Let'Swift 2019 키노트
Let'Swift 2019 키노트Let'Swift 2019 키노트
Let'Swift 2019 키노트Jung Kim
 
Letswift19-clean-architecture
Letswift19-clean-architectureLetswift19-clean-architecture
Letswift19-clean-architectureJung Kim
 
Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰
Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰
Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰Jung Kim
 
Letswift18 키노트
Letswift18 키노트Letswift18 키노트
Letswift18 키노트Jung Kim
 
개발자를 위한 넓고 얕은 지식
개발자를 위한 넓고 얕은 지식개발자를 위한 넓고 얕은 지식
개발자를 위한 넓고 얕은 지식Jung Kim
 
스위프트를 여행하는 히치하이커를 위한 스타일 안내
스위프트를 여행하는 히치하이커를 위한 스타일 안내스위프트를 여행하는 히치하이커를 위한 스타일 안내
스위프트를 여행하는 히치하이커를 위한 스타일 안내Jung Kim
 
Let'Swift 17 키노트
Let'Swift 17 키노트Let'Swift 17 키노트
Let'Swift 17 키노트Jung Kim
 
마스터즈 오픈세미나 - 소프트웨어가좋아요
마스터즈 오픈세미나 - 소프트웨어가좋아요마스터즈 오픈세미나 - 소프트웨어가좋아요
마스터즈 오픈세미나 - 소프트웨어가좋아요Jung Kim
 
소프트웨어로 미래를 준비하는 사람들
소프트웨어로 미래를 준비하는 사람들소프트웨어로 미래를 준비하는 사람들
소프트웨어로 미래를 준비하는 사람들Jung Kim
 
Developerway-2016-camp
Developerway-2016-campDeveloperway-2016-camp
Developerway-2016-campJung Kim
 
Swift internals
Swift internalsSwift internals
Swift internalsJung Kim
 
Swift2 smalltalk osxdev
Swift2 smalltalk osxdevSwift2 smalltalk osxdev
Swift2 smalltalk osxdevJung Kim
 
모바일 트렌드와 iOS
모바일 트렌드와 iOS모바일 트렌드와 iOS
모바일 트렌드와 iOSJung Kim
 
개발자로 살아가는 길, 그리고 NEXT
개발자로 살아가는 길, 그리고 NEXT개발자로 살아가는 길, 그리고 NEXT
개발자로 살아가는 길, 그리고 NEXTJung Kim
 
차세대컴파일러, VM의미래: 애플 오픈소스 LLVM
차세대컴파일러, VM의미래: 애플 오픈소스 LLVM차세대컴파일러, VM의미래: 애플 오픈소스 LLVM
차세대컴파일러, VM의미래: 애플 오픈소스 LLVMJung Kim
 

More from Jung Kim (15)

Let'Swift 2019 키노트
Let'Swift 2019 키노트Let'Swift 2019 키노트
Let'Swift 2019 키노트
 
Letswift19-clean-architecture
Letswift19-clean-architectureLetswift19-clean-architecture
Letswift19-clean-architecture
 
Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰
Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰
Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰
 
Letswift18 키노트
Letswift18 키노트Letswift18 키노트
Letswift18 키노트
 
개발자를 위한 넓고 얕은 지식
개발자를 위한 넓고 얕은 지식개발자를 위한 넓고 얕은 지식
개발자를 위한 넓고 얕은 지식
 
스위프트를 여행하는 히치하이커를 위한 스타일 안내
스위프트를 여행하는 히치하이커를 위한 스타일 안내스위프트를 여행하는 히치하이커를 위한 스타일 안내
스위프트를 여행하는 히치하이커를 위한 스타일 안내
 
Let'Swift 17 키노트
Let'Swift 17 키노트Let'Swift 17 키노트
Let'Swift 17 키노트
 
마스터즈 오픈세미나 - 소프트웨어가좋아요
마스터즈 오픈세미나 - 소프트웨어가좋아요마스터즈 오픈세미나 - 소프트웨어가좋아요
마스터즈 오픈세미나 - 소프트웨어가좋아요
 
소프트웨어로 미래를 준비하는 사람들
소프트웨어로 미래를 준비하는 사람들소프트웨어로 미래를 준비하는 사람들
소프트웨어로 미래를 준비하는 사람들
 
Developerway-2016-camp
Developerway-2016-campDeveloperway-2016-camp
Developerway-2016-camp
 
Swift internals
Swift internalsSwift internals
Swift internals
 
Swift2 smalltalk osxdev
Swift2 smalltalk osxdevSwift2 smalltalk osxdev
Swift2 smalltalk osxdev
 
모바일 트렌드와 iOS
모바일 트렌드와 iOS모바일 트렌드와 iOS
모바일 트렌드와 iOS
 
개발자로 살아가는 길, 그리고 NEXT
개발자로 살아가는 길, 그리고 NEXT개발자로 살아가는 길, 그리고 NEXT
개발자로 살아가는 길, 그리고 NEXT
 
차세대컴파일러, VM의미래: 애플 오픈소스 LLVM
차세대컴파일러, VM의미래: 애플 오픈소스 LLVM차세대컴파일러, VM의미래: 애플 오픈소스 LLVM
차세대컴파일러, VM의미래: 애플 오픈소스 LLVM
 

Recently uploaded

Electronically Controlled suspensions system .pdf
Electronically Controlled suspensions system .pdfElectronically Controlled suspensions system .pdf
Electronically Controlled suspensions system .pdfme23b1001
 
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)Dr SOUNDIRARAJ N
 
Introduction-To-Agricultural-Surveillance-Rover.pptx
Introduction-To-Agricultural-Surveillance-Rover.pptxIntroduction-To-Agricultural-Surveillance-Rover.pptx
Introduction-To-Agricultural-Surveillance-Rover.pptxk795866
 
welding defects observed during the welding
welding defects observed during the weldingwelding defects observed during the welding
welding defects observed during the weldingMuhammadUzairLiaqat
 
TechTAC® CFD Report Summary: A Comparison of Two Types of Tubing Anchor Catchers
TechTAC® CFD Report Summary: A Comparison of Two Types of Tubing Anchor CatchersTechTAC® CFD Report Summary: A Comparison of Two Types of Tubing Anchor Catchers
TechTAC® CFD Report Summary: A Comparison of Two Types of Tubing Anchor Catcherssdickerson1
 
Arduino_CSE ece ppt for working and principal of arduino.ppt
Arduino_CSE ece ppt for working and principal of arduino.pptArduino_CSE ece ppt for working and principal of arduino.ppt
Arduino_CSE ece ppt for working and principal of arduino.pptSAURABHKUMAR892774
 
8251 universal synchronous asynchronous receiver transmitter
8251 universal synchronous asynchronous receiver transmitter8251 universal synchronous asynchronous receiver transmitter
8251 universal synchronous asynchronous receiver transmitterShivangiSharma879191
 
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdf
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdfCCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdf
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdfAsst.prof M.Gokilavani
 
Application of Residue Theorem to evaluate real integrations.pptx
Application of Residue Theorem to evaluate real integrations.pptxApplication of Residue Theorem to evaluate real integrations.pptx
Application of Residue Theorem to evaluate real integrations.pptx959SahilShah
 
Architect Hassan Khalil Portfolio for 2024
Architect Hassan Khalil Portfolio for 2024Architect Hassan Khalil Portfolio for 2024
Architect Hassan Khalil Portfolio for 2024hassan khalil
 
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsyncWhy does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsyncssuser2ae721
 
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETE
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETEINFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETE
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETEroselinkalist12
 
Past, Present and Future of Generative AI
Past, Present and Future of Generative AIPast, Present and Future of Generative AI
Past, Present and Future of Generative AIabhishek36461
 
Concrete Mix Design - IS 10262-2019 - .pptx
Concrete Mix Design - IS 10262-2019 - .pptxConcrete Mix Design - IS 10262-2019 - .pptx
Concrete Mix Design - IS 10262-2019 - .pptxKartikeyaDwivedi3
 
Indian Dairy Industry Present Status and.ppt
Indian Dairy Industry Present Status and.pptIndian Dairy Industry Present Status and.ppt
Indian Dairy Industry Present Status and.pptMadan Karki
 
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort service
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort serviceGurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort service
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort servicejennyeacort
 
Risk Assessment For Installation of Drainage Pipes.pdf
Risk Assessment For Installation of Drainage Pipes.pdfRisk Assessment For Installation of Drainage Pipes.pdf
Risk Assessment For Installation of Drainage Pipes.pdfROCENODodongVILLACER
 

Recently uploaded (20)

young call girls in Green Park🔝 9953056974 🔝 escort Service
young call girls in Green Park🔝 9953056974 🔝 escort Serviceyoung call girls in Green Park🔝 9953056974 🔝 escort Service
young call girls in Green Park🔝 9953056974 🔝 escort Service
 
young call girls in Rajiv Chowk🔝 9953056974 🔝 Delhi escort Service
young call girls in Rajiv Chowk🔝 9953056974 🔝 Delhi escort Serviceyoung call girls in Rajiv Chowk🔝 9953056974 🔝 Delhi escort Service
young call girls in Rajiv Chowk🔝 9953056974 🔝 Delhi escort Service
 
Electronically Controlled suspensions system .pdf
Electronically Controlled suspensions system .pdfElectronically Controlled suspensions system .pdf
Electronically Controlled suspensions system .pdf
 
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
 
Introduction-To-Agricultural-Surveillance-Rover.pptx
Introduction-To-Agricultural-Surveillance-Rover.pptxIntroduction-To-Agricultural-Surveillance-Rover.pptx
Introduction-To-Agricultural-Surveillance-Rover.pptx
 
welding defects observed during the welding
welding defects observed during the weldingwelding defects observed during the welding
welding defects observed during the welding
 
TechTAC® CFD Report Summary: A Comparison of Two Types of Tubing Anchor Catchers
TechTAC® CFD Report Summary: A Comparison of Two Types of Tubing Anchor CatchersTechTAC® CFD Report Summary: A Comparison of Two Types of Tubing Anchor Catchers
TechTAC® CFD Report Summary: A Comparison of Two Types of Tubing Anchor Catchers
 
Arduino_CSE ece ppt for working and principal of arduino.ppt
Arduino_CSE ece ppt for working and principal of arduino.pptArduino_CSE ece ppt for working and principal of arduino.ppt
Arduino_CSE ece ppt for working and principal of arduino.ppt
 
8251 universal synchronous asynchronous receiver transmitter
8251 universal synchronous asynchronous receiver transmitter8251 universal synchronous asynchronous receiver transmitter
8251 universal synchronous asynchronous receiver transmitter
 
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdf
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdfCCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdf
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdf
 
Application of Residue Theorem to evaluate real integrations.pptx
Application of Residue Theorem to evaluate real integrations.pptxApplication of Residue Theorem to evaluate real integrations.pptx
Application of Residue Theorem to evaluate real integrations.pptx
 
Architect Hassan Khalil Portfolio for 2024
Architect Hassan Khalil Portfolio for 2024Architect Hassan Khalil Portfolio for 2024
Architect Hassan Khalil Portfolio for 2024
 
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsyncWhy does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
 
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETE
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETEINFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETE
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETE
 
Past, Present and Future of Generative AI
Past, Present and Future of Generative AIPast, Present and Future of Generative AI
Past, Present and Future of Generative AI
 
Concrete Mix Design - IS 10262-2019 - .pptx
Concrete Mix Design - IS 10262-2019 - .pptxConcrete Mix Design - IS 10262-2019 - .pptx
Concrete Mix Design - IS 10262-2019 - .pptx
 
Indian Dairy Industry Present Status and.ppt
Indian Dairy Industry Present Status and.pptIndian Dairy Industry Present Status and.ppt
Indian Dairy Industry Present Status and.ppt
 
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort service
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort serviceGurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort service
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort service
 
POWER SYSTEMS-1 Complete notes examples
POWER SYSTEMS-1 Complete notes  examplesPOWER SYSTEMS-1 Complete notes  examples
POWER SYSTEMS-1 Complete notes examples
 
Risk Assessment For Installation of Drainage Pipes.pdf
Risk Assessment For Installation of Drainage Pipes.pdfRisk Assessment For Installation of Drainage Pipes.pdf
Risk Assessment For Installation of Drainage Pipes.pdf
 

Swift와 Objective-C를 함께 쓰는 방법

  • 2. * “Using Swift with Cocoa and Objective-C” / .
  • 4. Interacting with Objective-C APIs - (instancetype)init; - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style; init() { /* ... */ } init(frame: CGRect, style: UITableViewStyle) { /* ... */ } UITableView *myTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped]; let myTableView: UITableView = UITableView(frame: .zero, style: .grouped) let myTextField = UITextField(frame: CGRect(x: 0.0, y: 0.0, width: 200.0, height: 40.0)) Initialization • Objective-C • Swift
  • 5. Interacting with Objective-C APIs UIColor *color = [UIColor colorWithRed:0.5 green:0.0 blue:0.5 alpha:1.0]; let color = UIColor(red: 0.5, green: 0.0, blue: 0.5, alpha: 1.0) Convenience Initializers • Objective-C • Swift To be used with the same syntax as initializers.
  • 6. Interacting with Objective-C APIs if let image = UIImage(contentsOfFile: "MyImage.png") { // loaded the image successfully } else { // could not load the image } Failable Initialization • Objective-C • Swift Initializers directly return the object they initialize. To inform the caller when initialization has failed, an Objective-C initializer can return nil.
  • 7. Interacting with Objective-C APIs Nullability Properties • Swift • Objective-C @property (nullable) id nullableProperty; @property (nonnull) id nonNullProperty; @property id unannotatedProperty; NS_ASSUME_NONNULL_BEGIN - (id)returnsNonNullValue; - (void)takesNonNullParameter:(id)value; NS_ASSUME_NONNULL_END - (nullable id)returnsNullableValue; - (void)takesNullableParameter:(nullable id)value; - (id)returnsUnannotatedValue; - (void)takesUnannotatedParameter:(id)value; var nullableProperty: Any? var nonNullProperty: Any var unannotatedProperty: Any! func returnsNonNullValue() -> Any func takesNonNullParameter(value: Any) func returnsNullableValue() -> Any? func takesNullableParameter(value: Any?) func returnsUnannotatedValue() -> Any! func takesUnannotatedParameter(value: Any!)
  • 8. Interacting with Objective-C APIs Accessing Properties • readonly = computed property { get } • weak = weak (weak var) • assign, copy, strong, unsafe_unretained • Class = Type • Atomic • Accessor (getter= / setter=)
  • 9. Interacting with Objective-C APIs myTableView.insertSubview(mySubview, at: 2) Working with Methods • Objective-C • Swift [myTableView insertSubview:mySubview atIndex:2]; myTableView.layoutIfNeeded() Can call Objective-C methods from Swift using dot syntax.
  • 10. Interacting with Objective-C APIs var x: Any = "hello" as String x as? String // String with value "hello" x as? NSString // NSString with value "hello" x = "goodbye" as NSString x as? String // String with value "goodbye" x as? NSString // NSString with value "goodbye" id • Objective-C • Swift The Objective-C id type is imported by Swift as the Any type.
  • 11. Interacting with Objective-C APIs let userDefaults = UserDefaults.standard let lastRefreshDate = userDefaults.object(forKey: "LastRefreshDate") // lastRefreshDate is of type Any? if let date = lastRefreshDate as? Date { print("(date.timeIntervalSinceReferenceDate)") } Downcasting Any let myDate = lastRefreshDate as! Date let timeInterval = myDate.timeIntervalSinceReferenceDate let myDate = lastRefreshDate as! String // Error Forced downcast operator (as!) Forced downcast error Conditional type cast operator (as?)
  • 12. Interacting with Objective-C APIs var myObject: AnyObject = UITableViewCell() myObject = NSDate() let futureDate = myObject.addingTimeInterval(10) let timeSinceNow = myObject.timeIntervalSinceNow Dynamic Method Lookup & Optional chaining AnyObject type lookup @objc method dynamically myObject.character(at: 5) // crash, myObject doesn't respond to that method let myCount = myObject.count // myCount has Int? type and nil value let myChar = myObject.character?(at: 5) // myChar has unichar? type and nil value if let fifthCharacter = myObject.character?(at: 5) { print("Found (fifthCharacter) at index 5") } // conditional branch not executed
  • 13. Interacting with Objective-C APIs Bridging Optionals to Nonnullable Objects @implementation OptionalBridging + (void)logSomeValue:(nonnull id)valueFromSwift { if ([valueFromSwift isKindOfClass: [NSNull class]]) { os_log(OS_LOG_DEFAULT, "Received an NSNull value."); } else { os_log(OS_LOG_DEFAULT, "%s", [valueFromSwift UTF8String]); } } @end let someValue: String? = "Bridge me, please." let nilValue: String? = nil OptionalBridging.logSomeValue(someValue as Any) // String OptionalBridging.logSomeValue(nilValue as Any) // an NSNull value. Optional nil NSNull , Optional unwrapped value [T?] => NSArray<T>
  • 14. Interacting with Objective-C APIs Lightweight Generics @property NSArray<NSDate *> *dates; @property NSCache<NSObject *, id<NSDiscardableContent>> *cachedData; @property NSDictionary <NSString *, NSArray<NSLocale *>> *supportedLocales; var dates: [Date] var cachedData: NSCache<AnyObject, NSDiscardableContent> var supportedLocales: [String: [Locale]] • Objective-C • Swift
  • 15. Interacting with Objective-C APIs Generic Class @interface List<T: id<NSCopying>> : NSObject - (List<T> *)listByAppendingItemsInList:(List<T> *)otherList; @end @interface ListContainer : NSObject - (List<NSValue *> *)listOfValues; @end @interface ListContainer (ObjectList) - (List *)listOfObjects; @end • Objective-C • Swift class List<T: NSCopying> : NSObject { func listByAppendingItemsInList(otherList: List<T>) -> List<T> } class ListContainer : NSObject { func listOfValues() -> List<NSValue> } extension ListContainer { func listOfObjects() -> List<NSCopying> }
  • 16. Interacting with Objective-C APIs Extensions (of existing classes, structures…) extension UIBezierPath { convenience init(triangleSideLength: CGFloat, origin: CGPoint) { self.init() let squareRoot = CGFloat(sqrt(3.0)) let altitude = (squareRoot * triangleSideLength) / 2 move(to: origin) addLine(to: CGPoint(x: origin.x + triangleSideLength, y: origin.y)) addLine(to: CGPoint(x: origin.x + triangleSideLength / 2, y: origin.y + altitude)) close() } } • Swift
  • 17. Interacting with Objective-C APIs Closures & Blocks void (^completionBlock)(NSData *) = ^(NSData *data) { // ... } • Swift • Objective-C let completionBlock: (Data) -> Void = { data in // ... } __weak typeof(self) weakSelf = self; self.block = ^{ __strong typeof(self) strongSelf = weakSelf; [strongSelf doSomething]; }; self.closure = { [unowned self] in self.doSomething() }
  • 18. Interacting with Objective-C APIs Object Comparison • Swift • Objective-C equality : ( -isEqual: ) identity : equality (==) : (Equatable ) == Operator isEqual: isEqual: identity (===) : === Operator
  • 19. Interacting with Objective-C APIs Hashing • Swift • Objective-C @property NSDictionary *unqualifiedDictionary; @property NSDictionary<NSString *, NSDate *> *qualifiedDictionary; @property NSSet *unqualifiedSet; @property NSSet<NSString *> *qualifiedSet; var unqualifiedDictionary: [AnyHashable: Any] var qualifiedDictionary: [String: Date] var unqualifiedSet: Set<AnyHashable> var qualifiedSet: Set<String>
  • 20. Interacting with Objective-C APIs Excludes Swift-only • Generics • Tuples • Enumerations defined in Swift without Int raw value type • Structures defined in Swift • Top-level functions defined in Swift • Global variables defined in Swift • Typealiases defined in Swift • Swift-style variadics • Nested types • Curried functions
  • 21. Interacting with Objective-C APIs Swift Type Compatibility class Jukebox: NSObject { var library: Set<String> var nowPlaying: String? var isCurrentlyPlaying: Bool { return nowPlaying != nil } class var favoritesPlaylist: [String] { // return an array of song names } init(songs: String...) { self.library = Set<String>(songs) } func playSong(named name: String) throws { // play song or throw an error if unavailable } } @interface Jukebox : NSObject @property (nonatomic, strong, nonnull) NSSet<NSString *> *library; @property (nonatomic, copy, nullable) NSString *nowPlaying; @property (nonatomic, readonly, getter=isCurrentlyPlaying) BOOL currentlyPlaying; @property (nonatomic, class, readonly, nonnull) NSArray<NSString *> * favoritesPlaylist; - (nonnull instancetype)initWithSongs:(NSArray<NSString *> * __nonnull)songs OBJC_DESIGNATED_INITIALIZER; - (BOOL)playSong:(NSString * __nonnull)name error:(NSError * __nullable * __null_unspecified)error; @end
  • 22. Interacting with Objective-C APIs Configuring Swift Interfaces @objc(Color) enum Цвет: Int { @objc(Red) case Красный @objc(Black) case Черный } @objc(Squirrel) class Белка: NSObject { @objc(color) var цвет: Цвет = .Красный @objc(initWithName:) init (имя: String) { // ... } @objc(hideNuts:inTree:) func прячьОрехи(количество: Int, вДереве дерево: Дерево) { // ... } }
  • 23. Interacting with Objective-C APIs Selectors import UIKit class MyViewController: UIViewController { let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50)) override init?(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) let action = #selector(MyViewController.tappedButton) myButton.addTarget(self, action: action, forControlEvents: .touchUpInside) } func tappedButton(sender: UIButton?) { print("tapped button") } required init?(coder: NSCoder) { super.init(coder: coder) } }
  • 24. Interacting with Objective-C APIs Unsafe Invocation of Objective-C Methods let string: NSString = "Hello, Cocoa!" let selector = #selector(NSString.lowercased(with:)) let locale = Locale.current if let result = string.perform(selector, with: locale) { print(result.takeUnretainedValue()) } // Prints "hello, cocoa!" let array: NSArray = ["delta", "alpha", "zulu"] // Not a compile-time error because NSDictionary has this selector. let selector = #selector(NSDictionary.allKeysForObject) // Raises an exception because NSArray does not respond to this selector. array.perform(selector) Perform Selector Unsafe invocation
  • 25. Interacting with Objective-C APIs Keys & Key Paths class Person: NSObject { var name: String var friends: [Person] = [] var bestFriend: Person? = nil init(name: String) { self.name = name } } let gabrielle = Person(name: "Gabrielle") let jim = Person(name: "Jim") let yuanyuan = Person(name: "Yuanyuan") gabrielle.friends = [jim, yuanyuan] gabrielle.bestFriend = yuanyuan #keyPath(Person.name) // "name" gabrielle.value(forKey: #keyPath(Person.name)) // "Gabrielle" #keyPath(Person.bestFriend.name) // "bestFriend.name" gabrielle.value(forKeyPath: #keyPath(Person.bestFriend.name)) // "Yuanyuan" #keyPath(Person.friends.name) // "friends.name" gabrielle.value(forKeyPath: #keyPath(Person.friends.name)) // ["Yuanyuan", "Jim"]
  • 26. Objective-C Behavior Inheriting from Objective-C Classes @IBDesignable, @IBInpectable let myPersonClass: AnyClass? = NSClassFromString("MyGreatApp.Person")
  • 27. Working with Cocoa Frameworks Foundation
  • 28. Working with Cocoa Frameworks Core Foundation CFStringRef StringByAddingTwoStrings(CFStringRef s1, CFStringRef s2) func StringByAddingTwoStrings(_: CFString!, _: CFString!) -> Unmanaged<CFString>! { // ... } let memoryManagedResult = StringByAddingTwoStrings(str1, str2).takeUnretainedValue() CFTypeRef remaps to the AnyObject CFStringRef remaps to the CFString class takeRetainedValue()
  • 29. Working with Cocoa Frameworks Unified Logging import os.log os_log("This is a log message.”) let fileSize = 1234567890 os_log("Finished downloading file. Size: %{iec-bytes}d", fileSize) os_log("This is additional info that may be helpful for troubleshooting.", type: .info) let customLog = OSLog("com.your_company.your_subsystem_name.plist", "your_category_name") os_log("This is info that may be helpful during development or debugging.", log: customLog, type: .debug)
  • 30. Working with Cocoa Frameworks Cocoa structure NSValue MKCoordinateSpan NSRange CLLocationCoordinate2D CATransform3D, CGAffineTransform CGPoint, CGRect, CGSize, CGVector CMTimeMapping, CMTimeRange, CMTime SCNMatrix4, SCNVector3, SCNVector4 UIEdgeInsets, UIOffset NSValue
  • 31. Adopting Cocoa Design Patterns Delegation 1)Check that myDelegate is not nil. 2)Check that myDelegate implements the method window:willUseFullScreenContentSize:. 3)If 1 and 2 hold true, invoke the method and assign the result of the method to the value named fullScreenSize. 4)Print the return value of the method. class MyDelegate: NSObject, NSWindowDelegate { func window(_ window: NSWindow, willUseFullScreenContentSize proposedSize: NSSize) -> NSSize { return proposedSize } } //… myWindow.delegate = MyDelegate() if let fullScreenSize = myWindow.delegate?.window(myWindow, willUseFullScreenContentSize: mySize) { print(NSStringFromSize(fullScreenSize)) }
  • 32. Adopting Cocoa Design Patterns Lazy Initialization @property NSXMLDocument *XML; - (NSXMLDocument *)XML { if (_XML == nil) { _XML = [[NSXMLDocument alloc] initWithContentsOfURL:[[Bundle mainBundle] URLForResource:@"/path/to/resource" withExtension:@"xml"] options:0 error:nil]; } return _XML; } lazy var XML: XMLDocument = try! XMLDocument(contentsOf: Bundle.main.url(forResource: "document", withExtension: "xml")!, options: 0) • Objective-C • Swift
  • 33. Adopting Cocoa Design Patterns Lazy property var pattern: String lazy var regex: NSRegularExpression = try! NSRegularExpression(pattern: self.pattern, options: []) lazy var currencyFormatter: NumberFormatter = { let formatter = NumberFormatter() formatter.numberStyle = .currency formatter.currencySymbol = "¤" return formatter }() • Swift use self-evaluating closure
  • 34. Adopting Cocoa Design Patterns Error Handling NSFileManager *fileManager = [NSFileManager defaultManager]; NSURL *fromURL = [NSURL fileURLWithPath:@"/path/to/old"]; NSURL *toURL = [NSURL fileURLWithPath:@"/path/to/new"]; NSError *error = nil; BOOL success = [fileManager moveItemAtURL:fromURL toURL:toURL error:&error]; if (!success) { NSLog(@"Error: %@", error.domain); } • Swift • Objective-C let fileManager = FileManager.default let fromURL = URL(fileURLWithPath: "/path/to/old") let toURL = URL(fileURLWithPath: "/path/to/new") do { try fileManager.moveItem(at: fromURL, to: toURL) } catch let error as NSError { print("Error: (error.domain)") }
  • 35. Adopting Cocoa Design Patterns Converting errors to Optional values • Swift • Objective-C NSFileManager *fileManager = [NSFileManager defaultManager]; NSURL *tmpURL = [fileManager URLForDirectory:NSCachesDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil]; if (tmpURL != nil) { // ... } let fileManager = FileManager.default if let tmpURL = try? fileManager.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: true) { // ... }
  • 36. Adopting Cocoa Design Patterns Throwing error • Swift • Objective-C // an error occurred if (errorPtr) { *errorPtr = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCannotOpenFile userInfo:nil]; } // an error occurred throw NSError(domain: NSURLErrorDomain, code: NSURLErrorCannotOpenFile, userInfo: nil)
  • 37. Adopting Cocoa Design Patterns Key-value Observing KVO with a Swift class inherits from NSObject class 1) Add dynamic modifier to any property 2) Create a global context variable 3) Add an observer for the key-path, override the observeValue() method and remove the observer in deinit. class MyObjectToObserve: NSObject { dynamic var myDate = NSDate() func updateDate() { myDate = NSDate() } } private var myContext = 0 class MyObserver: NSObject { var objectToObserve = MyObjectToObserve() override init() { super.init() objectToObserve.addObserver(self, forKeyPath: #keyPath(MyObjectToObserve.myDate), options: .new, context: &myContext) } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if context == &myContext { if let newValue = change?[.newKey] { print("Date changed: (newValue)”) } } else { super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) } } deinit { objectToObserve.removeObserver(self, forKeyPath: #keyPath(MyObjectToObserve.myDate), context: &myContext) } }
  • 38. Adopting Cocoa Design Patterns Undo architecture Create an undo operation using an NSInvocation @IBOutlet var remainingLabel: NSTextView! func mark(task: Task, asCompleted completed: Bool) { if let target = undoManager?.prepare(withInvocationTarget: self) as? ToDoListController { target.mark(task: task, asCompleted: !completed) undoManager?.setActionName(NSLocalizedString("todo.task.mark", comment: "Mark As Completed")) } task.completed = completed tableView.reloadData() let numberRemaining = tasks.filter{ $0.completed }.count remainingLabel.string = String(format: NSLocalizedString("todo.task.remaining", comment: "Tasks Remaining: %d"), numberRemaining) }
  • 39. Adopting Cocoa Design Patterns Singleton initialization in a call the dispatch_once function + (instancetype)sharedInstance { static id _sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _sharedInstance = [[self alloc] init]; }); return _sharedInstance; } class Singleton { static let sharedInstance = Singleton() } class Singleton { static let sharedInstance: Singleton = { let instance = Singleton() // setup code return instance }() }
  • 40. Adopting Cocoa Design Patterns Introspection use the isKindOfClass: method or conformsToProtocol: method if object is UIButton { // object is of type UIButton } else { // object is not of type UIButton } if let button = object as? UIButton { // object is successfully cast to type UIButton and bound to button } else { // object could not be cast to type UIButton } if let dataSource = object as? UITableViewDataSource { // object conforms to UITableViewDataSource and is bound to dataSource } else { // object not conform to UITableViewDataSource } • Swift • Objective-C
  • 41. Adopting Cocoa Design Patterns Serialization To encode and decode objects to and from architecture-independent representations. Use NSJSONSerialization and NSPropertyListSerialization import Foundation import CoreLocation struct Venue { enum Category: String { case entertainment case food case nightlife case shopping } var name: String var coordinates: CLLocationCoordinate2D var category: Category } { "name": "Caffè Macs", "coordinates": { "lat": 37.330576, "lng": -122.029739 }, "category": "food" }
  • 42. Adopting Cocoa Design Patterns Serialization : Initializer init?(attributes: [String: Any]) { guard let name = attributes["name"] as? String, let coordinates = attributes["coordinates"] as? [String: Double], let latitude = coordinates["lat"], let longitude = coordinates["lng"], let category = Category(rawValue: attributes["category"] as? String ?? "Invalid") else { return nil } self.name = name self.coordinates = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) self.category = category } let JSON = "{"name": "Caffè Macs","coordinates": {"lat": 37.330576,"lng": -122.029739}, "category": "food"}" let data = JSON.data(using: String.Encoding.utf8)! let attributes = try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any] let venue = Venue(attributes: attributes)! print(venue.name) // Prints "Caffè Macs" Initialize with Dictionary<String, Any> Create a Venue from a JSON representation
  • 43. Adopting Cocoa Design Patterns Serialization : Validating enum ValidationError: Error { case missing(String) case invalid(String) } init(attributes: [String: Any]) throws { guard let name = attributes["name"] as? String else { throw ValidationError.missing("name") } guard let coordinates = attributes["coordinates"] as? [String: Double] else { throw ValidationError.missing("coordinates") } guard let latitude = coordinates["lat"], let longitude = coordinates["lng"] else { throw ValidationError.invalid("coordinates") } guard let categoryName = attributes["category"] as? String else { throw ValidationError.missing("category") } guard let category = Category(rawValue: categoryName) else { throw ValidationError.invalid("category") } self.name = name self.coordinates = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) self.category = category }
  • 44. Adopting Cocoa Design Patterns Localization use NSLocalizedString, NSLocalizedStringFromTable, NSLocalizedStringFromTableInBundle, NSLocalizedStringWithDefaultValue • Objective-C • Swift A single function: NSLocalizedString(_:tableName:bundle:value:comment:) let format = NSLocalizedString("Hello, %@!", comment: "Hello, {given name}!") let name = "Mei" let greeting = String(format: format, arguments: [name as CVarArg]) print(greeting) // Prints "Hello, Mei!" if let path = Bundle.main.path(forResource: "Localization", ofType: "strings", inDirectory: nil, forLocalization: "ja"), let bundle = Bundle(path: path) { let translation = NSLocalizedString("Hello", bundle: bundle, comment: "") print(translation) } // Prints " "
  • 45. Adopting Cocoa Design Patterns API Availability use respondsToSelector: and instancesRespondToSelector: methods • Objective-C • Swift let locationManager = CLLocationManager() if #available(iOS 8.0, macOS 10.10, *) { locationManager.requestWhenInUseAuthorization() } if ([CLLocationManager instancesRespondToSelector:@selector(requestWhenInUseAuthorization)]) { // Method is available for use. } else { // Method is not available. } let locationManager = CLLocationManager() guard #available(iOS 8.0, macOS 10.10, *) else { return } locationManager.requestWhenInUseAuthorization()
  • 46. Adopting Cocoa Design Patterns Processing Command-Line Arguments for argument in CommandLine.arguments { print(argument) } // prints "/path/to/app" // prints "--argumentName" // prints "value" $ /path/to/app --argumentName value
  • 47. Interacting with C APIs Primitive Types C Type Swift Type bool CBool char, signed char CChar unsigned char CUnsignedChar short CShort unsigned short CUnsignedShort int CInt unsigned int CUnsignedInt long CLong unsigned long CUnsignedLong long long CLongLong unsigned long long CUnsignedLongLong wchar_t CWideChar char16_t CChar16 char32_t CChar32 float CFloat double CDouble
  • 48. Interacting with C APIs Importing Constant Enumerations and Structures Annotate an typedef declaration with the NS_STRING_ENUM or NS_EXTENSIBLE_STRING_ENUM • Objective-C • Swift struct TrafficLightColor: RawRepresentable { typealias RawValue = String init(rawValue: RawValue) var rawValue: RawValue { get } static var red: TrafficLightColor { get } static var yellow: TrafficLightColor { get } static var green: TrafficLightColor { get } } typedef NSString * TrafficLightColor NS_STRING_ENUM; TrafficLightColor const TrafficLightColorRed; TrafficLightColor const TrafficLightColorYellow; TrafficLightColor const TrafficLightColorGreen;
  • 49. Interacting with C APIs Functions Any function declared in a C header as a Swift global function. • Objective-C • Swift func product(_ multiplier: Int32, _ multiplicand: Int32) -> Int32 func quotient(_ dividend: Int32, _ divisor: Int32, _ remainder: UnsafeMutablePointer<Int32>) -> Int32 func createPoint2D(_ x: Float, _ y: Float) -> Point2D func distance(_ from: Point2D, _ to: Point2D) -> Float int product(int multiplier, int multiplicand); int quotient(int dividend, int divisor, int *remainder); struct Point2D createPoint2D(float x, float y); float distance(struct Point2D from, struct Point2D to);
  • 50. Interacting with C APIs Variadic Functions Call C variadic functions, such as vasprintf, using the getVaList() or withVaList() func swiftprintf(format: String, arguments: CVarArg...) -> String? { return withVaList(arguments) { va_list in var buffer: UnsafeMutablePointer<Int8>? = nil return format.withCString { CString in guard vasprintf(&buffer, CString, va_list) != 0 else { return nil } return String(validatingUTF8: buffer!) } } } print(swiftprintf(format: "√2 ≅ %g", arguments: sqrt(2.0))!) // Prints "√2 ≅ 1.41421"
  • 51. Interacting with C APIs Structures Any C Structure declared in a C header as a Swift structure. struct Color { float r, g, b; }; typedef struct Color Color; public struct Color { var r: Float var g: Float var b: Float init() init(r: Float, g: Float, b: Float) } • Swift
  • 52. Interacting with C APIs Importing Functions as Type Members Use CF_SWIFT_NAME macro in you own code Color ColorCreateWithCMYK(float c, float m, float y, float k) CF_SWIFT_NAME(Color.init(c:m:y:k:)); float ColorGetHue(Color color) CF_SWIFT_NAME(getter:Color.hue(self:)); void ColorSetHue(Color color, float hue) CF_SWIFT_NAME(setter:Color.hue(self:newValue:)); Color ColorDarkenColor(Color color, float amount) CF_SWIFT_NAME(Color.darken(self:amount:)); extern const Color ColorBondiBlue CF_SWIFT_NAME(Color.bondiBlue); Color ColorGetCalibrationColor(void) CF_SWIFT_NAME(getter:Color.calibration()); Color ColorSetCalibrationColor(Color color) CF_SWIFT_NAME(setter:Color.calibration(newValue:)); extension Color { init(c: Float, m: Float, y: Float, k: Float) var hue: Float { get set } func darken(amount: Float) -> Color static var bondiBlue: Color static var calibration: Color } • Swift
  • 53. Interacting with C APIs Enumerations Any C enumeration marked with the NS_ENUM macro as a Swift Enumeration(Int) typedef NS_ENUM(NSInteger, UITableViewCellStyle) { UITableViewCellStyleDefault, UITableViewCellStyleValue1, UITableViewCellStyleValue2, UITableViewCellStyleSubtitle }; enum UITableViewCellStyle: Int { case `default` case value1 case value2 case subtitle } • Swift let cellStyle: UITableViewCellStyle = .default
  • 54. Interacting with C APIs Enumerations : Option Sets Any C enumeration marked with the NS_OPTIONS macro as a Swift option set. typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) { UIViewAutoresizingNone = 0, UIViewAutoresizingFlexibleLeftMargin = 1 << 0, UIViewAutoresizingFlexibleWidth = 1 << 1, UIViewAutoresizingFlexibleRightMargin = 1 << 2, UIViewAutoresizingFlexibleTopMargin = 1 << 3, UIViewAutoresizingFlexibleHeight = 1 << 4, UIViewAutoresizingFlexibleBottomMargin = 1 << 5 }; public struct UIViewAutoresizing : OptionSet { public init(rawValue: UInt) public static var flexibleLeftMargin: UIViewAutoresizing { get } public static var flexibleWidth: UIViewAutoresizing { get } public static var flexibleRightMargin: UIViewAutoresizing { get } public static var flexibleTopMargin: UIViewAutoresizing { get } public static var flexibleHeight: UIViewAutoresizing { get } public static var flexibleBottomMargin: UIViewAutoresizing { get } } • Swift
  • 55. Interacting with C APIs Unions Swift imports C unions as Swift structures, not support unions. union SchroedingersCat { bool isAlive; bool isDead; }; struct SchroedingersCat { var isAlive: Bool { get set } var isDead: Bool { get set } init(isAlive: Bool) init(isDead: Bool) init() } • Swift
  • 56. Interacting with C APIs Unnamed Structure and Union Fields C struct and union types can define fields that have no name or that are of an unnamed type. struct Cake { union { int layers; double height; }; struct { bool icing; bool sprinkles; } toppings; }; var simpleCake = Cake() simpleCake.layers = 5 print(simpleCake.toppings.icing) // Prints "false" let cake = Cake( .init(layers: 2), toppings: .init(icing: true, sprinkles: false) ) print("The cake has (cake.layers) layers.") // Prints "The cake has 2 layers." print("Does it have sprinkles?", cake.toppings.sprinkles ? "Yes." : "No.") // Prints "Does it have sprinkles? No."
  • 57. Interacting with C APIs Pointers C Syntax Swift Syntax const Type * UnsafePointer<Type> Type * UnsafeMutablePointer<Type> C Syntax Swift Syntax Type * const * UnsafePointer<Type> Type * __strong * UnsafeMutablePointer<Type> Type ** AutoreleasingUnsafeMutablePointer<Type> C Syntax Swift Syntax const void * UnsafePointer void * UnsafeMutablePointer For return types, variables, and arguments For class types For pointers to untyped, raw memory
  • 58. Interacting with C APIs Constant Pointers func takesAPointer(_ p: UnsafePointer<Float>) { // ... } var x: Float = 0.0 takesAPointer(&x) takesAPointer([1.0, 2.0, 3.0]) var x: Float = 0.0, y: Int = 0 takesARawPointer(&x) takesARawPointer(&y) takesARawPointer([1.0, 2.0, 3.0] as [Float]) let intArray = [1, 2, 3] takesARawPointer(intArray) func takesARawPointer(_ p: UnsafeRawPointer?) { // ... }
  • 59. Interacting with C APIs Mutable Pointers func takesAMutablePointer(_ p: UnsafeMutablePointer<Float>) { // ... } var x: Float = 0.0 var a: [Float] = [1.0, 2.0, 3.0] takesAMutablePointer(&x) takesAMutablePointer(&a) var x: Float = 0.0, y: Int = 0 var a: [Float] = [1.0, 2.0, 3.0], b: [Int] = [1, 2, 3] takesAMutableRawPointer(&x) takesAMutableRawPointer(&y) takesAMutableRawPointer(&a) takesAMutableRawPointer(&b) func takesAMutableRawPointer(_ p: UnsafeMutableRawPointer?) { // ... }
  • 60. Interacting with C APIs Autoreleasing Pointers func takesAnAutoreleasingPointer(_ p: AutoreleasingUnsafeMutablePointer<NSDate?>) { // ... } var x: NSDate? = nil takesAnAutoreleasingPointer(&x)
  • 61. Interacting with C APIs Function Pointers func customCopyDescription(_ p: UnsafeRawPointer?) -> Unmanaged<CFString>? { // return an Unmanaged<CFString>? value } var callbacks = CFArrayCallBacks( version: 0, retain: nil, release: nil, copyDescription: customCopyDescription, equal: { (p1, p2) -> DarwinBoolean in // return Bool value } ) var mutableArray = CFArrayCreateMutable(nil, 0, &callbacks) C function pointers are imported into Swift as closures with C function pointer calling convention, denoted by the @convention(c) attribute.
  • 62. Interacting with C APIs Buffer Pointers & Null Pointers Buffer Pointers : Used for low-level access to a region of memory. UnsafeBufferPointer UnsafeMutableBufferPointer UnsafeRawBufferPointer UnsafeMutableRawBufferPointer Objective-C Syntax Swift Syntax const Type * _Nonnull UnsafePointer<Type> const Type * _Nullable UnsafePointer<Type>? const Type * _Null_unspecified UnsafePointer<Type>! Null Pointers Pointers Arithmatic let pointer: UnsafePointer<Int8> let offsetPointer = pointer + 24 // offsetPointer is 24 strides ahead of pointer
  • 63. Interacting with C APIs Data Type Size Calculation In C, the sizeof and alignof operators return the size and alignment In Swift, you use MemoryLayout<T> to access the memory layout of the parameterized type T through the size, stride, and alignment properties. print(MemoryLayout<timeval>.size) // Prints "16" print(MemoryLayout<timeval>.stride) // Prints "16" print(MemoryLayout<timeval>.alignment) // Prints "8" let sockfd = socket(AF_INET, SOCK_STREAM, 0) var optval = timeval(tv_sec: 30, tv_usec: 0) let optlen = socklen_t(MemoryLayout<timeval>.size) if setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &optval, optlen) == 0 { // ... }
  • 64. Interacting with C APIs Preprocessor Directives Simple Macro Complex Macro, no counterpart in Swift Conditional Compilation Blocks #if DEBUG_LOGGING print("Flag enabled.") #endif #define FADE_ANIMATION_DURATION 0.35 let FADE_ANIMATION_DURATION = 0.35 Function Valid arguments os() macOS, iOS, watchOS, tvOS, Linux arch() x86_64, arm, arm64, i386 swift() >= followed by a version number #if arch(arm) || arch(arm64) #if swift(>=3.0) print("Using Swift 3 ARM code") #else print("Using Swift 2.2 ARM code") #endif #elseif arch(x86_64) print("Using 64-bit x86 code.") #else print("Using general code.") #endif
  • 66. Mix and Match Overview
  • 67. Swift & Objective-C in the Same Project Importing Objective-C into Swift rely on an Objective-C bridging header to expose those files to Swift {product module name} + "-Bridging-Header.h" ex. = CodesquadApp CodesquadApp-Bridging-Header.h To import Objective-C code into Swift from the same target 1) In your Objective-C bridging header file, import every Objective-C header 2) In Build Settings > Swift Compiler - Code Generation, make sure the Objective-C Bridging Header build setting has a path to the bridging header file
  • 68. Swift & Objective-C in the Same Project Importing Swift into Objective-C rely on an Xcode-generated header file to expose those files to Objective-C {product module name} + "-Swift.h" ex. = CodesquadApp CodesquadApp-Swift.h The generated header contains interfaces for Swift declarations marked with the public or open modifier. An umbrella header for your Swift code Marked with the internal modifier if your app target has bridging header. To import Swift code into Objective-C from the same target #import "ProductModuleName-Swift.h"
  • 69. Swift & Objective-C in the Same Project Importing External Frameworks Swift code import FrameworkName @import FrameworkName; Objective-C code Import into Swift Import into Objective-C Any language framework import FrameworkName @import FrameworkName;
  • 70. Swift & Objective-C in the Same Project Using Swift from Objective-C Swift class MySwiftClass *swiftObject = [[MySwiftClass alloc] init]; [swiftObject swiftMethod]; // MyObjcClass.h @class MySwiftClass; @protocol MySwiftProtocol; @interface MyObjcClass : NSObject - (MySwiftClass *)returnSwiftClassInstance; - (id <MySwiftProtocol>)returnInstanceAdoptingSwiftProtocol; // ... @end Referencing a Swift Class or Protocol in an Objective-C Header
  • 71. Swift & Objective-C in the Same Project Using Swift from Objective-C Declaring a Swift Protocol That Can Be Adopted by an Objective-C Class @objc public protocol MySwiftProtocol { func requiredMethod() @objc optional func optionalMethod() } // MyObjcClass.m #import "ProductModuleName-Swift.h" @interface MyObjcClass () <MySwiftProtocol> // ... @end @implementation MyObjcClass // ... @end Adopting a Swift Protocol in an Objective-C Implementation
  • 72. Swift & Objective-C in the Same Project Using Swift from Objective-C Declaring a Swift Error Type That Can Be Used from Objective-C @objc public enum CustomError: Int, Error { case a, b, c } // Project-Swift.h typedef SWIFT_ENUM(NSInteger, CustomError) { CustomErrorA = 0, CustomErrorB = 1, CustomErrorC = 2, }; static NSString * const CustomErrorDomain = @"Project.CustomError"; In generated header:
  • 73. Swift & Objective-C in the Same Project Overriding Swift Names for Objective-C Interfaces Class Factory Methods + (instancetype)recordWithRPM:(NSUInteger)RPM NS_SWIFT_NAME(init(rpm:)); + (id)recordWithQuality:(double)quality NS_SWIFT_NAME(record(quality:)); typedef NS_ENUM(NSInteger, ABCRecordSide) { ABCRecordSideA, ABCRecordSideB NS_SWIFT_NAME(flipSide), }; Enumerations Swift compiler automatically imports Objective-C code as conventional Swift code.
  • 74. Swift & Objective-C in the Same Project Making Objective-C Interfaces Unavailable in Swift Convenience Initializer + (instancetype)collectionWithValues:(NSArray *)values forKeys: (NSArray<NSCopying> *)keys NS_SWIFT_UNAVAILABLE("Use a dictionary literal instead"); Some Objective-C interfaces may not be suitable or necessary to be exposed as Swift Objective-C class providing a convenience initializer that takes variadic arguments for keys-value pairs may advise a Swift consumer to use a dictionary literal instead:
  • 75. Swift & Objective-C in the Same Project Refining Objective-C Declarations use the NS_REFINED_FOR_SWIFT macro on an Objective-C method declaration to provide a refined Swift interface in an extension @interface Color : NSObject - (void)getRed:(nullable CGFloat *)red green:(nullable CGFloat *)green blue:(nullable CGFloat *)blue alpha:(nullable CGFloat *)alpha NS_REFINED_FOR_SWIFT; @end extension Color { var RGBA: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { var r: CGFloat = 0.0 var g: CGFloat = 0.0 var b: CGFloat = 0.0 var a: CGFloat = 0.0 __getRed(red: &r, green: &g, blue: &b, alpha: &a) return (red: r, green: g, blue: b, alpha: a) } }
  • 76. Swift & Objective-C in the Same Project Troubleshooting Tips and Reminders