티스토리 뷰

출처

https://github.com/apple/swift-evolution/blob/master/proposals/0160-objc-inference.md


소개

Swift 3 에서 사용되었던 @objc 추론에 제한을 둡니다.
편의상, Swift 는 @objc 를 여러 곳에서 유추해왔었습니다.


변경 이유

1) Swift 의 @objc 에 대한 추론 규칙은 단순하며, 

@objc 가 유추되는 이유가 사용자에게 불명확할 수 있습니다.


2) 클래스가 많아질경우 실수로 Objective-C 충돌을 발생시키는 

Swift 클래스를 작성하기 쉽습니다.


3) Swift 코드 디자인 지침을 따랐지만 

Objective-C 코드 작성 규칙을 위반하는 경우가 있습니다.

아래와 같은 경우 명시적인 @objc 주석이 필요합니다.



class MyNumber : NSObject {

    init(_ int: Int) { }

    init(_ double: Double) { } // error: initializer 'init' with Objective-C selector 'init:'

    // conflicts with previous declaration with the same Objective-C selector

}




class MyNumber : NSObject {

    @objc(initWithInteger:) init(_ int: Int) { }

    @objc(initWithDouble:) init(_ double: Double) { }

}



4) 각각의 Objective-C entry point 에 cost 가 있다는 점입니다.

Swift 컴파일러는 Objective-C 호출 규칙에서 Swift 호출 규칙으로 변경하기 위한 

map 의 "thunk" method 를 만들어야합니다.


이런 "thunk" method 는 는 Objective-C metadata 에 기록되기 때문에 

binary 크기가 증가됩니다.

또한 dynamic linker 는 이런 thunk method 를 위해 

Objective-C metadata 를 정렬해야하기 때문에 

로드 시간에 약간의 영향을 줄 수 있습니다. 





해결 방안

1) @objc 추론을 프로그래밍 모델의 의미론적 일관성에 필요한 곳으로 제한합니다.
2) class, extension 에서의 새로운 annotation 을 추가하여 
@objc 추론을 보다 광범위하게 활성화 / 비활성화하려는 경우에 사용합니다.


dynamic, NSObject -derived classes no longer infers @objc

dynamic 으로 선언된 함수 or 변수나 NSObject 를 상속받은 Class 는
@objc 를 붙이지 않는이상 추론되지 않습니다.


class MyClass : NSObject {

    func foo() { }

    func bar() { }

}


class UnrelatedClass : NSObject {

    @objc func bar() { }

}


func test(object: AnyObject) {

    object.foo?()

    // Swift 3: can call method MyClass.foo()

    // Swift 4: compiler error, no @objc method "foo()"

    

    object.bar?()

    // Swift 3: can call MyClass.bar() or UnrelatedClass.bar()

    // Swift 4: can only call UnrelatedClass.bar()

}




class MySuperclass : NSObject { }


extension MySuperclass {

    func extMethod() { }

    // implicitly @objc in Swift 3, not in Swift 4

}


class MySubclass : MySuperclass {

    override func extMethod() { }

    // Swift 3: okay

    // Swift 4: error "declarations in extensions cannot override yet"

}




Re-enabling @objc inference within a class hierarchy

일부 라이브러리 및 시스템 (ex. XCTest ) 은 여전히 Objective-C 런타임의 내부 기능에 크게 의존합니다.
이러한 시스템을 지원하려면 @objcMembers 라는 annotation 을 사용하여
클래스, 확장자, 하위클래스 및 모든 확장자에 대한 @objc 유추를 다시 활성화합니다.


@objcMembers

class MyClass : NSObject {

    func foo() { }             // implicitly @objc

    

    func bar() -> (Int, Int{  }   // not @objc, because tuple returns

    // aren't representable in Objective-C

}


extension MyClass {

    func baz() { }   // implicitly @objc

}


class MySubClass : MyClass {

    func wibble() { }   // implicitly @objc

}


extension MySubClass {

    func wobble() { }   // implicitly @objc

}




Enabling/Disabling @objc inference within an extension

Objective C 에 원하는 method 만 노출시키고 싶을 때가 있습니다.
이를 위해 @objc, @nonobjc 를 지정할 수 있습니다.


class SwiftClass: NSObject { }


@objc extension SwiftClass {

    func foo() { }            // implicitly @objc

    @nonobjc func bar() -> (Int, Int) { return (0, 0) }  // error: tuple type (Int, Int) not

    // expressible in @objc. add @nonobjc or move this method to fix the issue

}


@objcMembers

class MyClass : NSObject {

    func wibble() { }    // implicitly @objc

}


@nonobjc extension MyClass {

    func wobble() { }    // not @objc, despite @objcMembers

}




Constructs that (still) infer @objc

기존에 유추되던 부분이 그대로 사용되는 곳도 있습니다.
@objc 가 선언된 method, protocol 을 상속, 구현하는 경우
@IBAction, @IBOutlet, @NSManaged, @GKInspectable, @IBInspectable 의 경우
@objc 로 유추됩니다.


class Super {

    @objc func foo() { }

}


class Sub : Super {

    /* inferred @objc */

    override func foo() { }

}




@objc protocol MyDelegate {

    func bar()

}


class MyClass : MyDelegate {

    /* inferred @objc */

    func bar() { }

}




Side benefit: more reasonable expectations


@objc protocol P { }


extension P {

    func bar() { }

}


class C : NSObject, P { }


let c = C()

print(c.responds(to: Selector("bar"))) // prints "false"





Limitation Activate Setting

Project -> Target -> Build Settings -> inference 검색 후
Swift 3 @objc Inference 를 On -> Default 로 변경
























공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함