[Swift] #selector, @objc

술술·2024년 3월 18일

TIL

목록 보기
8/21

#selector

우리는 iOS 개발에서 특정 Control에 target-action을 적용할 때 자연스럽게 Selector라는 타입의 객체(#selector(@objc method))를 사용합니다.

button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)

#selector 란?

메서드 주소를 통해 메서드를 가리키기 위한 기술

#selector( 메서드 )

물론 메서드 주소를 통해 메서드를 호출할 순 없다. 단순하게 메서드를 가리키는 것?
셀렉터는 속성에 접근이나 메서드를 호출하는게 아니다. 가리키기만 한다.
코드 영역의 메모리 주소를 가리켜서, (버튼이 눌렸을 때 해당 메서드를 실행시키기 위해) 연결시키는 기술

Objective-C에서의 Selector

사실 Selector는 원래 Objective-C에서 사용하던 기능입니다. 이는 특정 메서드를 컴파일타임에 동적으로 식별하고 참조하는 역할을 했습니다. 이러한 특징을 기반으로 Objective-C에서 동적으로 메서드를 동작시키려할 때 Selector를 사용했습니다. 반면 Swift에서는 이런 별도의 객체를 사용하지 않아도 메서드를 동적으로 동작시킬 수 있기 때문에 직접적으로 Selector를 필요로 하지는 않습니다.

Swift에서의 Selector

최근에는 주로 Swift로 iOS 개발을 진행하지만 여전히 많은 iOS의 API들이 Objective-C를 기반으로 동작하고 있습니다. 대표적인 예로 앞서 언급한 target-action 메커니즘이 내부적으로 Objective-C에 의존적으로 돌아갑니다. 따라서 Objective-C 기반 API에서 Selector 타입을 요구하는 경우, 이를 대체할 수 있는 타입을 Swift에서 제공할 수 있어야합니다.

그렇기 때문에 Swift에서 직접적으로 Selector를 사용하지는 않지만 Objective-C의 Selector와 유사한 기능을 하는 Selector를 필요로 했던 것입니다.

#selector의 사용

  • 클래스와 Objective-C 프로토콜에 포함된 멤버에만 적용 가능하다.
  • 구조체는 적용이 불가능하다.
  • 내부적으로 Objective-C프레임워크를 사용하고 있다.
  • @objc 특성을 추가해야지만 사용 가능하다.

셀렉터 내부에 메서드를 명시하게되면 해당 메서드를 가리키게 되고 이를 변수에 할당하면 셀렉터 구조체가 생성된다.

class Dog {
    var num = 1.0
    
    @objc var doubleNum: Double {
        get {
            return num * 2.0
        }
        set {
            num = newValue / 2.0
        }
    }
    
    @objc func run() {
        print("강아지가 달립니다.")
    }
}

// (계산)속성을 가르킬때
let eyesSelector = #selector(getter: Dog.doubleNum)
let nameSelector = #selector(setter: Dog.doubleNum)

// 메서드를 가르킬때
let runSelector = #selector(Dog.run)

계산속성도 따지고 보면 메서드이므로 계산속성도 가리킬 수 있다.
#selector(getter: Dog.doubleNum) 은 계산속성인 doubleNum의 getter(get)부분을 가리키게 되고,
#selector(setter: Dog.doubleNum) 은 계산속성인 doubleNum의 setter(set)부분을 가리키게 된다.

#selector(Dog.run)Dog클래스의 run메서드를 가리키게된다.

실제로 셀렉터는 버튼따위를 코드로 구현할 때 action과 연결시키기 위해 많이 사용된다.

셀렉터를 생성할 메서드는 @objc 를 붙여야한다

@objc func test() { print("test funtion") } let selector = #selector(test) button.addTarget(target: self, action: selector, for: .touchUpInside)

#selector() 에 순수 swift 함수를 전달하면 인식하지 못합니다.

Objective-C 에 인식시키기 위해서는 위 코드의 @objc test() {...} 처럼
메서드 앞에 @objc 특성을 추가해주어야 합니다.

@objc 의 필요성

컴파일 타임에 메서드를 바인딩하는 Swift와는 다르게 Objective-C는 런타임에 메서드를 바인딩합니다. 따라서 Swift에서 Objective-C에 의존적인 메서드에 사용할 때는 해당 메서드가 Objective-C와 유사한 방식으로 컴파일 되어야함을 컴파일러에게 알려주어야 합니다.

이를 의미하는 것이 @objc입니다. 이를 메서드 앞에 붙여주면 Swift로 작성된 코드를 Objective-C 런타임에서도 사용할 수 있게됩니다. (cf. 만약 class가 NSObject를 상속하고 있는 경우 해당 키워드가 필요하지 않습니다.)


출처

https://clamp-coding.tistory.com/392
https://inuplace.tistory.com/1072
https://woozzang.tistory.com/120

profile
Hello

0개의 댓글