Swift는 respondsToSelector에 해당하는 것은 무엇입니까?


195

나는 구글 검색했지만 그와 동등한 것이 무엇인지 알 수 없었습니다 respondsToSelector:.

이것이 내가 찾을 수있는 유일한 것 ( Swift alternatives to respondsToSelector :) 이지만 대리인의 존재를 확인하는 경우 내 경우에는 관련이 없습니다. 대리인이 없으며 새로운 API가 있는지 확인하고 싶습니다. 장치에서 실행 중이거나 이전 버전의 API로 폴백하지 않는 경우.


이 모든 것들은 옵션으로 대체되고 옵션 체인으로 연습됩니다
Jack

애플이 명시 적으로 사용하는 것이 좋습니다 점을 감안 NSClassFromString하고 respondsToSelector, 새롭게 구현 된 기능을 확인하기위한 다른 기계들, 내가 메커니즘은 이미 자리에, 또는 릴리스 전에있을 것 중 하나 믿고있어. Advanced Interop...WWDC 에서 비디오를 보십시오 .
David Berry

2
@Jack Wu 그러나 새로운 메소드가 UIApplication이나 UIViewController와 같은 근본적인 것에 도입 된 새로운 것이라면 어떨까요? 이러한 객체는 선택 사항이 아니며 새로운 방법은 선택 사항이 아닙니다. 예를 들어 UIApplcation : newVersionOfMethodX를 호출해야하는지 또는 UIApplication : deprecatedVersionOfMethodX를 호출해야하는지 어떻게 확인할 수 있습니까? (iOS 7의 Swift에서 앱을 빌드하고 실행할 수 있다는 것은 매우 일반적인 시나리오입니다)
Gruntcakes

API가 Apple API와 관련이 있습니까?
GoZoner

@PotassiumPermanganate-물론 대답이 '예, Apple API를 사용하고 있었다'라면 if #available(...)Swift 2.x respondsToSelector에서 처음 사용하지 않을 수 있습니다 . 그러나 당신은 그것을 알고있었습니다. ( apple.co/1SNGtMQ )
GoZoner

답변:


170

언급했듯이 Swift에서 대부분의 경우 ?선택적 unwrapper 연산자를 사용하여 필요한 것을 얻을 수 있습니다 . 이를 통해 객체가 존재하고 (아님 nil) 메소드가 구현 된 경우에만 객체에서 메소드를 호출 할 수 있습니다 .

여전히 필요한 경우 프로토콜의 respondsToSelector:일부로 여전히 존재 NSObject합니다.

respondsToSelector:Swift에서 Obj-C 유형을 호출 하는 경우 예상대로 작동합니다. 자신의 Swift 클래스에서 사용하는 경우 클래스가에서 파생되도록해야합니다 NSObject.

다음은 선택기에 응답하는지 확인할 수있는 Swift 클래스의 예입니다.

class Worker : NSObject
{
    func work() { }
    func eat(food: AnyObject) { }
    func sleep(hours: Int, minutes: Int) { }
}

let worker = Worker()

let canWork = worker.respondsToSelector(Selector("work"))   // true
let canEat = worker.respondsToSelector(Selector("eat:"))    // true
let canSleep = worker.respondsToSelector(Selector("sleep:minutes:"))    // true
let canQuit = worker.respondsToSelector(Selector("quit"))   // false

매개 변수 이름을 생략하지 않는 것이 중요합니다. 이 예에서, Selector("sleep::")이다 하지 동일 Selector("sleep:minutes:").


iOS8에서 UIApplication에 도입 된 새로운 방법이 있는지 확인하려고 노력하고 있으며 지금까지 운이 없습니다. 위의 방법에 따라 시도하는 방법은 다음과 같습니다. if present = UIApplication.sharedApplication (). respondsToSelector (Selector ( "redactedAsStillUnderNDA")). 그러나 컴파일 오류가 발생합니다. "조건부 바인딩의 바운드 값은 선택적인 유형이어야합니다."
Gruntcakes 2016 년

4
해당 줄을 분할 하거나let x = 부분을 제거해야합니다 . 기본적으로 if let x = y구조는 옵션 값 (와 유사한 !)의 랩을 해제합니다 . 에서 Bool되돌아 가기 때문에 respondsToSelector컴파일러는 결과가 선택적 유형 ( Bool?) 이 아니라고 불평합니다 .
Erik

어떻게 될까 var선언의? 그들은 여전히 ​​같은 방식으로 응답합니까? 오브젝티브 C에서 내가 할 수있는 if ( [obj respondsToSelector:@selector(setSomeVar:)] ) { ... }A의 someVar속성입니다. varSwift에서 s 와 동일한 방식으로 작동합니까 ?
Alejandro Iván

View 컨트롤러 인스턴스 옵션이 nil이 아니지만 메소드 또는 함수가 해당 컨트롤러에서 구현되지 않은 경우 어떻게됩니까? 객체가 선택기에 응답하는지 여부를 확인해야한다고 생각합니다.
Ashish Pisey

" 'UIViewController'유형의 값에 멤버 'respondsToSelector'가 없습니다. '
Michał Ziobro

59

실제 Swift 교체는 없습니다.

다음과 같은 방법으로 확인할 수 있습니다.

someObject.someMethod?()

someMethod객체에 정의 된 경우에만 메소드를 호출 someObject하지만 @objc메소드를로 선언 한 프로토콜 에만 사용할 수 있습니다 optional.

Swift는 본질적으로 안전한 언어이므로 메소드를 호출 할 때마다 Swift가 메소드가 있는지 알아야합니다. 런타임 검사가 불가능합니다. 임의의 개체에 대해 임의의 메서드를 호출 할 수는 없습니다.

Obj-C에서도 ARC와 잘 작동하지 않기 때문에 가능하면 이러한 것들을 피해야합니다 (ARC는에 대해 경고를 트리거 함 performSelector:).

그러나 사용 가능한 API를 확인할 때 인스턴스를 respondsToSelector:처리하는 경우 Swift를 사용 하더라도 여전히을 사용할 수 있습니다 NSObject.

@interface TestA : NSObject

- (void)someMethod;

@end

@implementation TestA

//this triggers a warning

@end   


var a = TestA()

if a.respondsToSelector("someMethod") {
   a.someMethod()
}

1
따라서 앱은 현재 실행중인 OS의 버전을 명시 적으로 알고 있어야합니까? iOS8에만 존재하고 이전 iOS7 버전을 사용하지 않는 메소드를 호출하고 싶습니다. 따라서 새로운 방법의 존재 여부를 확인하는 대신 iOS8을 사용하고 있는지 확인해야합니다. 스위프트는 좋지만 약간 어색한 것 같습니다.
Gruntcakes

@sulthan 나는 당신이 respondsToSelector:애플의 추천 으로 사용해서는 안된다고 말하면서 어디에서 왔는지 확실하지 않습니다 . 여기
David Berry

@David 네, respondsToSelector:실제로 가지고 있는 몇 가지 경우 중 하나를 발견했습니다 . 그러나 Swift 참조를 살펴보면 서로 다른 시스템 버전에 서브 클래스를 사용하는 것에 대해 이야기합니다.
Sulthan

OP가 말한 경우가 아니며 옵션 프로토콜 사례에 대해 이야기하는 경우 옵션 체인을 사용하여 명시 적으로 허용합니다 (지시 한대로). 어느 쪽이든, "Apple이 명시 적으로 말한 것을하지 말아야한다"고 말하는 것은 나쁜 조언처럼 보입니다. Apple은 런타임시 옵션 기능을 결정하고 실행하기위한 메커니즘을 "항상"제공했습니다.
David Berry

1
@Honey Swift에서는 일반적으로 가용성 지시문을 대신 사용합니다. 예를 들어 if #available(iOS 10) {메소드를 직접 호출합니다.
Sulthan

40

Swift 3 구문에 대해 2017 년 3 월 20 일 업데이트 :

선택적인 메소드가 존재하는지 걱정하지 않는다면 delegate?.optionalMethod?()

그렇지 않으면 사용하는 guard것이 가장 좋은 방법 일 것입니다.

weak var delegate: SomeDelegateWithOptionals?

func someMethod() {
    guard let method = delegate?.optionalMethod else {
        // optional not implemented
        alternativeMethod()
        return
    }
    method()
}

원래 답변 :

"if let"접근 방식을 사용하여 다음과 같은 선택적 프로토콜을 테스트 할 수 있습니다.

weak var delegate: SomeDelegateWithOptionals?

func someMethod() {
  if let delegate = delegate {
    if let theMethod = delegate.theOptionalProtocolMethod? {
      theMethod()
      return
    }
  }
  // Reaching here means the delegate doesn't exist or doesn't respond to the optional method
  alternativeMethod()
}

4
theMethod = delegate?를하자면. 선택적인 프로토콜 방법
john07

1
여러 후보자가있을 때 선택기 구문의 예 :let theMethod = delegate.userNotificationCenter(_:willPresent:withCompletionHandler:)
Cœur

11

NSObjectProtocol의 하위 프로토콜로 프로토콜을 정의 해야하는 것 같습니다 ... 그러면 respondsToSelector 메소드가 표시됩니다

@objc protocol YourDelegate : NSObjectProtocol
{
    func yourDelegateMethod(passObject: SomeObject)
}

@objc 만 지정하는 것만으로는 충분하지 않습니다. 실제 델리게이트는 NSObject의 서브 클래스입니다. 스위프트에서는 그렇지 않을 수도 있습니다.


10

테스트하려는 방법이 @objc 프로토콜 ( 선택 사항) 에서 선택적 방법 으로 정의 된 경우 옵션 체인 패턴을 다음과 같이 사용하십시오 .

if let result = object.method?(args) {
  /* method exists, result assigned, use result */
}
else { ... }

메소드가 returning으로 선언되면 다음을 Void사용하십시오.

if object.method?(args) { ... }

보다:

“선택적 체인을 통한 호출 방법”
발췌 : Apple Inc.“Swift Programming Language”
iBooks. https://itun.es/us/jEUH0.l


이것은 메소드가 무언가를 반환하는 경우에만 작동합니다. void 메소드라면 어떻게됩니까?
Gruntcakes

1
만약 void use가 간단하다면 if object.method?(args) { ... }– 메소드 호출이 존재 Void하는 경우 그렇지 않은 것을 반환 할 것입니다nil
GoZoner

1
그러나 그 결과 "유형이 프로토콜"논리 값 "을 따르지 않습니다"
Gruntcakes

참조 문서 (311-312 페이지)를 참조하십시오.
GoZoner 2016 년

"테스트중인 메소드가 @objc 프로토콜에서 선택적 메소드로 정의 된 경우"또는 object유형 AnyObject이있는 경우 @objc 메소드를 테스트 할 수 있습니다.
newacct 2016 년

9

함수는 Swift의 일류 유형이므로 프로토콜에 정의 된 선택적 함수가 nil과 비교하여 구현되었는지 확인할 수 있습니다.

if (someObject.someMethod != nil) {
    someObject.someMethod!(someArgument)
} else {
    // do something else
}

1
메서드가 오버로드되면 어떻게됩니까? 특정 정보를 어떻게 확인할 수 있습니까?
Nuno Gonçalves

8

swift3

메소드를 호출하려면 아래 코드를 실행하십시오.

self.delegate?.method?()


7

스위프트 2 년, 애플이라는 새로운 기능 도입 API availability checking에 대한 대체 될 수도 respondsToSelector:WWDC2015 세션 (106)에서 복사 코드 비교 다음 method.The을 스위프트의 새로운 기능 내가 당신을 도와 줄 알았는데 당신이 필요로하는 경우, 그것을 확인하시기 바랍니다 더 알고

오래된 접근법 :

@IBOutlet var dropButton: NSButton!
override func awakeFromNib() {
    if dropButton.respondsToSelector("setSpringLoaded:") {
        dropButton.springLoaded = true
    }
}

더 나은 접근 방식 :

@IBOutlet var dropButton: NSButton!
override func awakeFromNib() {
    if #available(OSX 10.10.3, *) {
        dropButton.springLoaded = true
    }
}

respondsToSelectorSwift 의 접근 방식을 사용하는 것보다 훨씬 나은 솔루션이라고 생각합니다 . 또한 선택기 검사가이 문제에 대한 최상의 솔루션이 아니기 때문입니다 (가용성 검사).
JanApotheker

6

스위프트 3.0

import UIKit

@objc protocol ADelegate : NSObjectProtocol {

    @objc optional func hi1()
    @objc optional func hi2(message1:String, message2:String)
}

class SomeObject : NSObject {

    weak var delegate:ADelegate?

    func run() {

        // single method
        if let methodHi1 = delegate?.hi1 {
            methodHi1()
        } else {
            print("fail h1")
        }

        // multiple parameters
        if let methodHi2 = delegate?.hi2 {
            methodHi2("superman", "batman")
        } else {
            print("fail h2")
        }
    }
}

class ViewController: UIViewController, ADelegate {

    let someObject = SomeObject()

    override func viewDidLoad() {
        super.viewDidLoad()

        someObject.delegate = self
        someObject.run()
    }

    // MARK: ADelegate
    func hi1() {

        print("Hi")
    }

    func hi2(message1: String, message2: String) {

        print("Hi \(message1) \(message2)")
    }
}

4

현재 (Swift 2.1) 세 가지 방법으로 확인할 수 있습니다.

  1. 사용 respondsToSelector가 @Erik_at_Digit 응답
  2. 사용 '?' 의해 답변을 @Sulthan

  3. 그리고 as?연산자 사용하기 :

    if let delegateMe = self.delegate as? YourCustomViewController
    {
       delegateMe.onSuccess()
    }

기본적으로 달성하려는 대상에 따라 다릅니다.

  • 예를 들어 앱 논리에서 일부 작업을 수행해야하고 대리자가 설정되지 않았거나 지정된 대리자가 onSuccess () 메서드 (프로토콜 메서드)를 구현하지 않은 경우 옵션 1과 3이 최선의 선택입니다. 스위프트 방식 인 옵션 3
  • 델리게이트가 nil이거나 메소드가 구현되지 않은 경우 아무 작업도 원하지 않으면 옵션 2를 사용하십시오.

2

방금 프로젝트에서 직접 구현합니다. 아래 코드를 참조하십시오. @Christopher Pickslay가 언급했듯이 함수는 일급 시민이므로 선택적 변수처럼 취급 될 수 있다는 것을 기억하는 것이 중요합니다.

@objc protocol ContactDetailsDelegate: class {

    optional func deleteContact(contact: Contact) -> NSError?
}

...

weak var delegate:ContactDetailsDelegate!

if let deleteContact = delegate.deleteContact {
    deleteContact(contact)
}

메서드가 오버로드되면 어떻게됩니까? 어떻게할까요?
Nuno Gonçalves

2

신속한 다른 구문 ..

 if let delegate = self.delegate, method = delegate.somemethod{
        method()
    }

2

이전 프로젝트를 Swift 3.2로 업데이트하기 시작했을 때 메소드를 변경해야했습니다.

respondsToSelector(selector)

에:

responds(to: selector)

0

guard let else위임 기능이 구현되지 않은 경우 기본 작업을 수행 할 수 있도록을 사용 합니다.

@objc protocol ViewController2Delegate: NSObjectProtocol {

    optional func viewController2(controller: ViewController2, didSomethingWithStringAndReturnVoid string: String)

    optional func viewController2(controller: ViewController2, didSomethingWithStringAndReturnString string: String) -> String
}

class ViewController2: UIViewController {

    weak var delegate: ViewController2Delegate?        

    @IBAction func onVoidButtonClicked(sender: AnyObject){

        if (delegate != nil && delegate!.respondsToSelector(Selector("viewController2:didSomethingWithStringAndReturnVoid:"))) {
            NSLog("ReturnVoid is implemented")

            delegate!.viewController2!(self, didSomethingWithStringAndReturnVoid: "dummy")
        }
        else{
            NSLog("ReturnVoid is not implemented")
            // Do something by default
        }
    }

    @IBAction func onStringButtonClicked(sender: AnyObject){

        guard let result = delegate?.viewController2?(self, didSomethingWithStringAndReturnString: "dummy") else {
            NSLog("ReturnString is not implemented")
            // Do something by default
            return
        }

        NSLog("ReturnString is implemented with result: \(result)")
    }
}

-1

스위프트 3 :

실험 계획안

@objc protocol SomeDelegate {
    @objc optional func method()
}

목적

class SomeObject : NSObject {

weak var delegate:SomeObject?

func delegateMethod() {

     if let delegateMethod = delegate?.method{
         delegateMethod()
     }else {
        //Failed
     }

   }

}

-4

동등한 것은? 운영자:

var value: NSNumber? = myQuestionableObject?.importantMethod()

importantMethod는 myQuestionableObject가 존재하고 구현 한 경우에만 호출됩니다.


그러나 myQuestionalObject가 UIApplication과 같고 (따라서 존재 여부를 확인하는 것이 의미가 없음) importandMethod ()가 iOS N에 도입 된 새로운 메소드이고 호출 할 수 있는지 또는 호출해야하는지 여부를 결정하려는 경우 iOS N-1에서 오래된 deprecatedImportantMethod ()?
Gruntcakes

2
당신은 또한 ?후 필요importantMethod
newacct
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.