์ ํ ๊ฐ๋ฐ ์ค ๊ณ ๊ฐ์ฌ์ ์์ฒญ์ ๋ฐ๋ผ Swift ์ธ์ด์ ๋์ํ๋ ์ผ์ด ๋ง์์ง๋ฉด์,
๊ธฐ์กด Objective-C๋ก ๊ตฌํ๋ ์ ํ ์์ฒด๋ฅผ Swift๋ก Converting ํ๋ ์์ ์ ํ๊ณ ์๋ค.
์ด ๊ณผ์ ์์ ํ ํ๋ก์ ํธ์์ Objective-C์ Swift๋ฅผ ํจ๊ป ์ฌ์ฉํ๊ณ ,
Swift๋ก ๋ง๋ Framework๋ฅผ Objective-C ํ๋ก์ ํธ์์
Objective-C๋ก ๋ง๋ Framework๋ฅผ Swift ํ๋ก์ ํธ์์ ํ ์คํธํด์ผ ํ๋ค.
์ด๋ ๊ฒ Swift์ Objective-C ๋ฅผ ํจ๊ป ์ฌ์ฉํ๊ธฐ ์ํด ์ค์ ํ ๊ฒ๋ค๊ณผ
๋ ์ธ์ด์ ์ฐจ์ด์ ์์ ๋ฐ์ํ๋ ๋ฌธ์ ์ ์ ๊ณต์ ํ๊ณ ์ ํ๋ค.
[Contents]
- Swift ํ๋ก์ ํธ์์ Objective-C ์ฌ์ฉํ๊ธฐ
- Swift ํ๋ก์ ํธ์์ Objective-C ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ (Import Objective-C into Swift)
- Objective-C ํ๋ก์ ํธ์์ Swift ์ฌ์ฉํ๊ธฐ
- Objective-C ํ๋ก์ ํธ์์ Swift ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ(Import Swift into Objective-C)
- Objective-C ํ๋ก์ ํธ์์ Swift Framework๋ฅผ ์ฌ์ฉํ๊ธฐ
- Swift, Objective-C๋ฅผ ๊ฐ์ด ์ฌ์ฉํ ๋ ์ฃผ์ํ ์
- enums in Swift and Objective-C
โญ๏ธ 1. Swift ํ๋ก์ ํธ์์ Objective-C ์ฌ์ฉํ๊ธฐ
๊ณต์ ๋ฌธ์ : https://developer.apple.com/documentation/swift/importing-objective-c-into-swift
1-1. Swift ํ๋ก์ ํธ์์ Objective-C ์์ค ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ (Import Objective-C into Swift)
1. ๋ธ๋ฆฌ์ง ํค๋ ํ์ผ(Bridging header) ์์ฑ
Swift code์์ Objective-C ์ฝ๋๋ฅผ ์ฐ๋ ค๋ฉด, Objcective-C Bridging header ๊ฐ ํ์ํ๋ค.
Xcode์์ ์ด ํค๋๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ์๋, ์๋ ๋ ๊ฐ์ง๊ฐ ์๋ค.
๋จผ์ , ์ค์ํํธ ํ๋ก์ ํธ์์ ์ค๋ธ์ ํฐ๋ธ-C ํ์ผ์ ์์ฑํ๋ฉด ์๋์ ๊ฐ์ ํ์ ์ ๋ณผ ์ ์๋ค.
1-1) ์ด๋, Create Bridging Header๋ฅผ ์ ํํ์ ๊ฒฝ์ฐ(์๋)
ํ์ผ์ ์์ฑํ ๊ณณ์ AppName-Bridging-Header.h ํ์ผ์ด ์์ฑ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
1-2) Don't Create๋ฅผ ์ ํํ๊ฑฐ๋ ํ์ ์ด ๋ณด์ด์ง ์์ ๊ฒฝ์ฐ(์๋)
AppName-Bridging-Header.h ํ์ผ์ ์ง์ ์์ฑํด์ค๋ค.
๋ค๋ง, ์ด ํ๋ก์ ํธ์์ ๋ธ๋ฆฟ์ง ํค๋ ํ์ผ์ ์ฌ์ฉํ๊ณ ์๋ค๋ ์ฌ์ค์ ๋ช
์ํด ์ฃผ๊ธฐ ์ํด์
'Project - Target - Build Settings - Objective-C Bridging Header'์ ํ์ผ์ ์์น/AppName-Bridging-Header.h ๋ฅผ ์ถ๊ฐ
*์ด๋, ๋ธ๋ฆฌ์ง ํค๋ ํ์ผ๋ช ์ "Project name"-Bridging-Header.h ์ด์ด์ผ ํจ!
์์ฑ๋ ํค๋ํ์ผ์ Build Settings์ ์ถ๊ฐํ์ฌ ์ปดํ์ผํ ๋ ์ฐธ์กฐ๋๋๋ก ํด์ผ ํ๋ค.
*์ฌ๋ฌ ๊ฐ target ์ด ์์ด ์ฌ๋ฌ ๊ฐ ๋ธ๋ฆฟ์ง ํค๋ ํ์ผ์ด ์์ฑ๋๋ ๊ฒฝ์ฐ!
"Project name"-Bridging-Header.h 1๊ฐ๋ฅผ ์ ์ธํ๊ณ ๋ค ์ญ์ ํ Build Setting์ ํด๋น ํ์ผ์ ๊ฒฝ๋ก(์๋๊ฒฝ๋ก)๋ฅผ ๋ฃ์ด์ฃผ์ด
๋ชจ๋ ํ๊น์ด ๊ฐ์ ๋ธ๋ฆฟ์ง ํค๋๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
2. ์ฌ์ฉํ๊ธฐ
์ด ํ์ผ ์์ ์๋์ ๊ฐ์ด Swift์์ ์ฌ์ฉํ ์ค๋ธ์ ํฐ๋ธ-C ํ์ผ์ ํค๋ ํ์ผ์ import ํด์ฃผ๋ฉด ๋๋ค.
#import "NewObjectiveCFile.h"
// MARK: - Models -
#import "User.h"
#import "Group.h"
// MARK: - Managers -
#import "AnalyticsManager.h"
#import "AlertManager.h"
+Swift์์ Objective-C ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ๋, NS_SWIFT_NAME ๋งคํฌ๋ก(preprocessor)๋ฅผ ์ฌ์ฉํ์ฌ ์ปค์คํ ๊ฐ๋ฅ!
์๋ฅผ ๋ค์ด, ์๋ ๋ฉ์๋๋ฅผ
+(void)SuperGoodAdditionFeature:(NSInteger)a (NSInteger)b;
์๋ Swift์์ ์ด ์ฝ๋๋ฅผ ์ฌ์ฉํ ๋,
let result = SuperGoodAdditionFeature(1, 2)
NS_SWIFT_NAME ๋งคํฌ๋ก ์ฌ์ฉํ์ฌ ์ฌ์ ์ํ์ฌ Swift ์ฉ ๋ณ๋ช ์ ๋ง๋ค์ด ์ค๋ค.
+(void)SuperGoodAdditionFeature:(NSInteger)a (NSInteger)b
NS_SWIFT_NAME(add(a:b:));
์ฌ์ ์ํ ์ด๋ฆ(renaming)์ผ๋ก์๋์ ๊ฐ์ด ์ฝ๋ฉ ๊ฐ๋ฅํ๋ค.
let result = add(a: 1,b: 2)
๊ณต์ ๋ฌธ์ : https://developer.apple.com/documentation/swift/renaming-objective-c-apis-for-swift
โญ๏ธ 2. Objective-C ํ๋ก์ ํธ์์ Swift ์ฌ์ฉํ๊ธฐ
๊ณต์ ๋ฌธ์ : https://developer.apple.com/documentation/swift/importing-swift-into-objective-c
2-1. Objective-C ํ๋ก์ ํธ์์ Swift ์์ค ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ(Import Swift into Objective-C)
1. 'Project - Target - Build Settings - Defines Module'์ Yes๋ก ์ค์
2. @objc ์์ฑ(attribute) ์ฌ์ฉ
Objective-C์์ ์ฌ์ฉํ Swift ํ์ผ์ ํด๋์ค๋ ํจ์๋ช ์์๋ @objc ์์ฑ์ ์ฌ์ฉํด์ Swift ํด๋์ค, ๋ฉ์๋, ์์ฑ์ Objective-C์์ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
์์ธํ ๋ด์ฉ : https://lxxyeon.tistory.com/95
์ด ์์ฑ์ compiler์๊ฒ Objective-C์์ ์์ฑ์ ๋ถ์ธ ๊ฒ์ ์ ๊ทผํ ๊ฒ์ ์๋ฆฌ๊ณ , ๋ง์ฝ Swift class๊ฐ Objective-C๋ฅผ ์์๋์๋ค๋ฉด, compiler๊ฐ ์๋์ผ๋ก @objc๋ฅผ ๋ถ์ฌ์ค๋ค. ์ด ์์ฑ์ 3๊ฐ์ง๋ก ์ฌ์ฉ๋๋๋ฐ,
- @objc : ๋ฉ์๋, ์์ฑ
- @objc(name) : ์ฌ์ฉํ ๋ฉ์๋๋ ์์ฑ์ ์ด๋ฆ์ ์ฌ์ ์(custom)ํด์ ์ฌ์ฉํ ์ ์๋ค.
@objc(sharedManager)
static let shared = MyManager()
์ ๋ณ์๋ฅผ Objective-C์์ ํธ์ถํ ๋,
[MyManager sharedManager]
๋ฉ์๋์ ํ๋ผ๋ฏธํฐ๋ ์ฌ์ ์ ๊ฐ๋ฅ!
@objc(processNotificationPayload:notificationType:)
static func processNotification(with payload: String, notificationType: NotificationType) {
...
}
- @objcMembers : ํด๋์ค์ ๋ชจ๋ ๋ฉค๋ฒ, ํ์ฅ, ํ์ ํด๋์ค, ํด๋์ค์ extensions
@objcMembers class MyController: UIViewController {
func login() {
}
}
๊ณต์๋ฌธ์ : https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes/#objc
์ด๋, ํด๋์ค๋ Objective-C ํด๋์ค(์: NSObject)๋ฅผ ์์๋ฐ์ ๊ตฌํํด์ผ ํ๋ค.
@objc(TestService)
class TestService: NSObject {
@objc static let shared = TestService()
@objc func sayHello() {
print("Hello!")
}
}
์ด์ Swift ์ฝ๋๋ฅผ ์ฌ์ฉํ๊ณ ์ถ์ Objective-C ํ์ผ์์ ํด๋น ์ฝ๋๋ฅผ ํธ์ถํด ๋ณด๋ฉด, ์๋์ ๊ฐ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
[[TestService shared] sayHello];
// error
Use of undeclared identifier 'TestService'
์ด ์ค๋ฅ๋ ์ฐ๋ฆฌ๊ฐ ํค๋ ํ์ผ์ ์ํฌํธ ํ์ง ์์์ ์๊ธด ์ค๋ฅ!!
๊ทธ๋ ๋ค๋ฉด ์ฐ๋ฆฌ๋ ํค๋ ํ์ผ์ ์๋ก ์์ฑํด์ผ ํ๋๋!
๊ทธ๋ด ํ์ ์์ด ์ฐ๋ฆฌ๊ฐ ์์์ Defines Module์ Yes๋ก ์ค์ ํด ๋์๊ธฐ ๋๋ฌธ์ ์ปดํ์ผํ๋ ๊ณผ์ ์์ XCode๊ฐ ํค๋ ํ์ผ์ ์๋์ผ๋ก ์์ฑํด ์ค๋ค.
3. ์ฌ์ฉํ Objective-C์ #import "{module name}-Swift.h" ์ถ๊ฐ
. h์์๋ ์ํ์ฐธ์กฐ(cyclical reference)๋ฅผ ๋ง๊ธฐ ์ํด Swift code๋ฅผ import ํ์ง ์๊ณ @class, @protocol๋ก ๋งํนํ๋ค.
// MyObjcClass.h
@class MySwiftClass;
@protocol MySwiftProtocol;
@interface MyObjcClass : NSObject
- (MySwiftClass *)returnSwiftClassInstance;
- (void)test;
- (id <MySwiftProtocol>)returnInstanceAdoptingSwiftProtocol;
// ...
@end
.m ํ์ผ์์ ์๋ ์์ฑ๋ ๋ธ๋ฆฟ์ง ํค๋ ํ์ผ(-Swift.h)์ import ํด์ค๋ค.
// .m
#import "MyObjcClass.h"
#import "ProductModuleName-Swift.h"
@implementation MyObjcClass
- (void) test {
MySwiftClass *module = [[MySwiftClass alloc] init];
[module test];
}
@end
4. ์ฌ์ฉํ๊ธฐ
2-2. Objective-C์์ Swift Framework๋ฅผ ์ฌ์ฉํ๊ธฐ
๋จผ์ ๊ฒฐ๋ก ์ Swift Framework ๋ด์ ๋ธ๋ฆฟ์ง ํค๋๋ฅผ ๋ง๋ค์ด์ ์ฌ์ฉํ Objective-C ์ฝ๋ ๋ด์ import๋ฅผ ํด์ฃผ๋ ๊ฒ์ด๋ค.
๊ทผ๋ฐ, ์ด๋, ์ง์ ๋ธ๋ฆฟ์ง ํค๋๋ฅผ ๋ง๋ค์ง ์๊ณ , ์ค์ ์ ํตํด ์๋์ผ๋ก ์์ฑํ๋ค.
HOW? Build Setting > SWIFT_INSTALL_OBJC_HEADER ๊ฒ์ > install Generated Header > Yes๋ก ์ค์ !!
build ๋ ํ๋ ์์ํฌ ๋ ํฌ์ ๊ฐ๋ฉด ์์ฑ๋ ํค๋ ํ์ผ์ด ์์์ ํ์ธ!
์ด ํค๋ํ์ผ์ด๋ฆ์ ์ฌ์ฉํ๊ณ ์ถ์ ๊ณณ์ import ํด์ฃผ๋ฉด ๋๋ค!
์ด ํค๋ํ์ผ ๋ํ Swift์ interface๋ฅผ ์ ์ํ๊ณ ์๊ณ , ์์ฑ๋ umbrella header๋ umbrella framework์ ๋ํ master header ๊ฐ ๋๋ค.
#import <Framework/Framework-Swift.h>
*umbrella framework๋ ์ฌ๋ฌ ํ๋ ์์ํฌ๋ฅผ ๊ทธ๋ฃนํ(subframework๋ค์ encapsulate) ํ ๊ฒ์ผ๋ก header file๋ค์ include ํ๊ณ ์๋ค.
Umbrella framework๋ ๋ด๋ถ์ ๊ตฌํ์ ์ ์จ๊ฒจ์ ํ์ํ interface ๋ง ์ ๊ณตํ ์ ์๊ณ ,
precompiled header๋ฅผ ์ฌ์ฉํด build ๋ ๋ ๋นจ๋ฆฌ ํ ์ ์๋ ์ฅ์ ์ด ์์.
โญ๏ธ 3. Swift, Objective-C๋ฅผ ๊ฐ์ด ์ฌ์ฉํ ๋ ์ฃผ์ํ ์ !
- Objective-C์์๋ ๊ตฌ์กฐ์ฒด์ ํํ์ด ํ์๋์ง ์๋๋ค.
- Swift์์ Tuple์ ์ด์ฉํ์ฌ ์ฌ๋ฌ ๊ฐ์ ํ ๋ฒ์ ๋๊ธธ ์ ์๋ค. ํ์ง๋ง Objective-C๋ ARC๊ฐ ์ ์ฉ๋ ์ดํ์ struct ๋ด๋ถ์ ํด๋์ค ํ์ ์ ์ฌ์ฉํ์ง ๋ชปํ๋๋ก ๊ธ์ง๋์ด ์์.
- Objective-C์ ์ ์ฉํ๋ฉด ์๋์ ๊ฐ์ ์๋ฌ ๋ฐ์ > unsafe_unretained ์ฌ์ฉํ์ฌ ํด๊ฒฐ ๊ฐ๋ฅ!
- Swift Tuples, Generics์ ํฌํจํ ์๋ ์ ํ๋ค์ @objc๋ฅผ ๋ถ์ฌ๋ Objective-C์์ ์ฌ์ฉํ ์ ์๋ค.
- ์ง์๋์ง ์๋ ์ ํ : https://stackoverflow.com/questions/26463487/swift-globals-and-global-functions-in-objective-c
- Objective-C๋ ํจ์๋ ๋ฉ์๋ ์ธ์์ default ๊ฐ์ ์ง์ํ์ง ์๋๋ค.
- Objective-C์์ ์ฌ์ฉํ Swift ํด๋์ค๋ฅผ Objective-C ํด๋์ค(์: NSObject)๋ฅผ ์์๋ฐ์ ๊ตฌํํด์ผ ํ๋ค.
- Any in Swift = id in Objective-C
- Objective-C์์๋ Swift ํด๋์ค๋ฅผ ์์ํ ์ ์๋ค. ๊ทธ๋ฌ๋ protocol์ ๊ตฌํ ๊ฐ๋ฅ!
- Objective-C ์์ฑ ์ค null ์ง์ ์๊ฐ ๋ช ์์ ์ผ๋ก ์ง์ ๋์ง ์์ผ๋ฉด, Swift์์๋ ์ต์ ๋๋ก ์ฒ๋ฆฌํ๋ค -> ์ธ๋ํ๋๋ค. -> ์ถฉ๋์ด ๋ฐ์ํ ์ ์์ต๋๋ค!
3-1.enums in Swift, Objective-C
IMPORTANT: Swift enums can't be used in Objective-C header files.
Objectiev-C์ Swift ์ด๊ฑฐํ์ ๋ถ์ผ์นํจ์ ๋ง์ถฐ๋ณด์.
๊ธฐ๋ณธ์ ์ธ Objectiev-C์ ์ด๊ฑฐํ์ ์๋ ์๋์ ๊ฐ๋ค.
typedef enum my_type {
MyTypeDefault = 0,
MyTypeSolo,
MyType
}MyType;
์ด๋ฐ ์์ผ๋ก ์ ์ธํ ๊ฒฝ์ฐ MyType์ด๋ผ๋ ํ์ ์ Swift์ enum๊ณผ๋ ๋ค๋ฅด๊ฒ struct ํํ๋ก ์ ์ธ๋์ด ๋ฒ๋ฆฐ๋ค.
๋ฐ๋ผ์, Swift์์ ์ฌ์ฉํ ๋, enum ์ค๋ฝ์ง ์์ ํํ์ธ ๊ฐ ํ๋์ ์ด๋ฆ ๊ทธ๋๋ก ์ ๊ทผํ๊ฒ ๋๋ค.
let type: MyType = MyTypeDefault
์ด๋ฅผ Swift์ ์ด์ธ๋ฆฌ๊ฒ ๊ตฌํํ๋ ค๋ฉด NS_ENUM ๋งคํฌ๋ก๋ฅผ ์ด์ฉํด ์ด๊ฑฐํ์ ์ ์ํ์ฌ ์์ ~!
typedef NS_ENUM(int, MyType) {
MyTypeDefault = 0,
MyTypeSolo,
MyType
};
์ด๋ ๊ฒ ๊ตฌํํ๋ฉด MyType์ Swift์ enumํ์์ผ๋ก ์ฌ์ ์๋์ด MyType ํ์ ์ธ์คํด์ค์ ๊ฐ์ .default, .solo ์ ๊ฐ์ด prefix๋ฅผ ์๋ตํ ํํ์ ์ด๋ฆ์ผ๋ก ์ธ ์ ์๋ค.
let type: MyType = .default
์ถ๊ฐ๋ก, ์๋์ ๊ฐ์ด ํน์ดํ ์ด๋ฆ์ ์ถ๊ฐ๋ ์ํฉ๋ ์ดํด๋ณด์.
๋ง์ง๋ง์ ์ถ๊ฐํ AnotherTypeSuperSolo๋ผ๋ ์ด๋ฆ์ ์ด์ธ๋ฆฌ์ง ์๊ฒ. AnotherTypeSuperSolo์ ๊ฐ์ ์ฌ๋ณผ๋ก ๋ฐ์ ์ ๊ทผํ ์๊ฐ ์์ ๊ฒ์ด๋ค.
typedef NS_ENUM(int, MyType) {
MyTypeDefault = 0,
MyTypeSolo,
MyType,
AnotherTypeSuperSolo
};
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ NS_SWIFT_NAME์ ์ฌ์ฉํ์ฌ ํด๊ฒฐ ๊ฐ๋ฅํ๋ค.
typedef NS_ENUM(int, MyType) {
MyTypeDefault = 0,
MyTypeSolo,
MyType,
AnotherTypeSuperSolo NS_SWIFT_NAME(anotherTypeSuperSolo)
};
์ด์ ์ถ๊ฐํ๋ ๋ง์ง๋ง ์ด๋ฆ์ Swift ์ค๋ฝ๊ฒ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค.
let firstType: MyType = .default
let secondType: MyType = .anotherTypeSuperSolo