developer tip

@selector () in Swift?

optionbox 2020. 10. 2. 22:02
반응형

@selector () in Swift?


나는 만들려고 해요 NSTimer에서을 Swift하지만 몇 가지 문제가 있어요.

NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)

test() 같은 클래스의 함수입니다.


편집기에서 오류가 발생합니다.

제공된 인수를 허용하는 'init'에 대한 오버로드를 찾을 수 없습니다.

나는 변경하는 경우 selector: test()selector: nil오류 사라집니다.

난 노력 했어:

  • selector: test()
  • selector: test
  • selector: Selector(test())

그러나 아무것도 작동하지 않으며 참조에서 해결책을 찾을 수 없습니다.


Swift 자체 는 선택기를 사용하지 않습니다. Objective-C에서 선택기를 사용하는 몇 가지 디자인 패턴은 Swift에서 다르게 작동합니다. (예를 들어, 프로토콜 유형 또는 is/ as테스트 에 대해 선택적 체인을 respondsToSelector:사용 performSelector:하고 더 나은 유형 / 메모리 안전성 대신 가능한 곳에서 클로저를 사용하십시오 .)

그러나 타이머 및 대상 / 동작 패턴을 포함하여 선택기를 사용하는 중요한 ObjC 기반 API가 여전히 많이 있습니다. Swift는 Selector이러한 작업을위한 유형을 제공합니다 . (Swift는 ObjC의 SEL유형 대신 자동으로 이것을 사용 합니다.)

Swift 2.2 (Xcode 7.3) 이상 (Swift 3 / Xcode 8 및 Swift 4 / Xcode 9 포함) :

표현식을 Selector사용하여 Swift 함수 유형에서 를 생성 할 수 있습니다 #selector.

let timer = Timer(timeInterval: 1, target: object,
                  selector: #selector(MyClass.test),
                  userInfo: nil, repeats: false)
button.addTarget(object, action: #selector(MyClass.buttonTapped),
                 for: .touchUpInside)
view.perform(#selector(UIView.insertSubview(_:aboveSubview:)),
             with: button, with: otherButton)

이 접근 방식의 장점은 무엇입니까? 함수 참조는 Swift 컴파일러에 의해 확인되므로 #selector실제로 존재하고 선택 자로 사용할 수있는 클래스 / 메서드 쌍으로 만 표현식을 사용할 수 있습니다 (아래 "선택기 사용 가능성"참조). 또한 함수 유형 명명에 대한 Swift 2.2+ 규칙에 따라 필요한만큼만 함수 참조를 자유롭게 만들 수 있습니다 .

( @selector()컴파일러의 -Wundeclared-selector검사는 명명 된 선택자가 존재하는지 만 확인 하기 때문에 이것은 실제로 ObjC의 지시문 보다 개선 된 것입니다. 사용자가 전달하는 Swift 함수 참조 #selector는 존재, 클래스의 멤버쉽 및 유형 서명을 확인합니다.)

#selector표현식에 전달하는 함수 참조에 대한 몇 가지 추가주의 사항이 있습니다 .

  • 기본 이름이 동일한 여러 함수 는 함수 참조 (예 : insertSubview(_:at:)vs insertSubview(_:aboveSubview:))에 대해 앞서 언급 한 구문을 사용하여 매개 변수 레이블로 구분할 수 있습니다 . 그러나 함수에 매개 변수가없는 경우이를 명확히하는 유일한 방법 as은 함수의 유형 서명 (예 : foo as () -> ()vs foo(_:)) 과 함께 캐스트 를 사용하는 것입니다 .
  • Swift 3.0 이상에는 속성 getter / setter 쌍에 대한 특수 구문이 있습니다. 예를 들어,가 주어지면 또는 var foo: Int을 사용할 수 있습니다 .#selector(getter: MyClass.foo)#selector(setter: MyClass.foo)

일반 사항 :

사례 #selector연구 및 명명을하지 않습니다는 : 때때로 당신은 (동적 ObjC 런타임에 등록 된 방법으로, 예를 들어)와 선택기를 만들 수있는 함수 참조가 없습니다. 이 경우 Selector문자열에서를 생성 할 수 있습니다 . 예를 들어 Selector("dynamicMethod:")— 컴파일러의 유효성 검사를 잃어도됩니다. 이를 수행 할 때 :각 매개 변수에 대한 콜론 ( )을 포함하여 ObjC 명명 규칙을 따라야 합니다.

선택기 가용성 : 선택기가 참조하는 메서드는 ObjC 런타임에 노출되어야합니다. Swift 4에서 ObjC에 노출 된 모든 메소드는 @objc속성으로 시작하는 선언이 있어야 합니다. (이전 버전에서는 경우에 따라 무료로 해당 속성을 얻었지만 이제 명시 적으로 선언해야합니다.)

기억 private도, 심볼이 런타임에 노출되지 않습니다 - 당신의 방법은 적어도 있어야 internal가시성.

주요 경로 : 선택기와 관련이 있지만 동일하지는 않습니다. Swift 3에도 이것에 대한 특별한 구문이 있습니다 : 예 : chris.valueForKeyPath(#keyPath(Person.friends.firstName)). 자세한 내용은 SE-0062 를 참조하십시오. 그리고 KeyPathSwift 4 에는 더 많은 것들이 있으므로 적절한 경우 선택기 대신 올바른 KeyPath 기반 API를 사용하고 있는지 확인하십시오.

당신은 아래 선택기에 대한 자세한 읽을 수 오브젝티브 C API를 상호 작용코코아 및 목표 - C와 스위프트를 사용 .

참고 : Swift 2.2 이전에는을 Selector준수 StringLiteralConvertible하므로 선택기를 사용하는 API에 베어 문자열이 전달되는 이전 코드를 찾을 수 있습니다. Xcode에서 "Convert to Current Swift Syntax"를 실행하여 #selector.


다음 Selector은 Swift 에서 클래스 를 사용하는 방법에 대한 간단한 예입니다 .

override func viewDidLoad() {
    super.viewDidLoad()

    var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))
    self.navigationItem.rightBarButtonItem = rightButton
}

func method() {
    // Something cool here   
}

문자열로 전달 된 메서드가 작동하지 않으면 컴파일 타임이 아닌 런타임에 실패하고 앱이 충돌합니다. 조심해


또한 (Swift) 클래스가 Objective-C 클래스의 하위 클래스가 아닌 경우 대상 메서드 이름 문자열 끝에 콜론이 있어야하며 대상 메서드와 함께 @objc 속성을 사용해야합니다.

var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))

@objc func method() {
    // Something cool here   
} 

그렇지 않으면 런타임에 "Unrecognised Selector"오류가 발생합니다.


Swift 2.2+ 및 Swift 3 업데이트

새로운 #selector표현식을 사용하면 문자열 리터럴을 사용할 필요가 없으므로 오류 발생 가능성이 줄어 듭니다. 참고로 :

Selector("keyboardDidHide:")

된다

#selector(keyboardDidHide(_:))

더보기 : Swift Evolution Proposal

참고 (Swift 4.0) :

사용 #selector하는 경우 기능을 다음과 같이 표시해야합니다.@objc

예:

@objc func something(_ sender: UIButton)


미래의 독자를 위해 나는 문제 unrecognised selector sent to instance가 발생했으며 대상 func을 비공개로 표시하여 발생한 오류를 발견했습니다 .

func 반드시 셀렉터에 대한 참조 목적으로 불릴 공개적으로 표시.


스위프트 4.0

아래와 같이 선택기를 만듭니다.

1. 다음과 같은 버튼에 이벤트를 추가합니다.

button.addTarget(self, action: #selector(clickedButton(sender:)), for: UIControlEvents.touchUpInside)

기능은 다음과 같습니다.

@objc func clickedButton(sender: AnyObject) {

}

다른 답변이 문제를 해결하지 않은 NSTimer에서 내가 가진 동일한 문제를 다른 사람이 가진 경우를 대비하여 NSObject에서 직접 또는 계층 구조에서 상속되지 않는 클래스를 사용하는 경우 언급하는 것이 정말 중요합니다 ( 예를 들어 수동으로 만든 신속한 파일), 다음과 같이 지정된 경우에도 다른 답변은 작동하지 않습니다.

let timer = NSTimer(timeInterval: 1, target: self, selector: "test", 
                    userInfo: nil, repeats: false)
func test () {}

클래스를 NSObject에서 상속하는 것 외에 다른 것을 변경하지 않고 "Unrecognized selector"오류가 발생하는 것을 중단하고 논리가 예상대로 작동하도록했습니다.


NSTimer에서 함수에 매개 변수를 전달하려는 경우 솔루션은 다음과 같습니다.

var somethingToPass = "It worked"

let timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: "tester:", userInfo: somethingToPass, repeats: false)

func tester(timer: NSTimer)
{
    let theStringToPrint = timer.userInfo as String
    println(theStringToPrint)
}

선택기 텍스트 (tester :)에 콜론을 포함하면 매개 변수가 userInfo에 들어갑니다.

함수는 NSTimer를 매개 변수로 취해야합니다. 그런 다음 userInfo를 추출하여 전달 된 매개 변수를 가져 오십시오.


선택자는 Objective-C에서 메서드 이름의 내부 표현입니다. Objective-C에서 "@selector (methodName)"은 소스 코드 메소드를 SEL의 데이터 유형으로 변환합니다. Swift에서 @selector 구문을 사용할 수 없기 때문에 (rickster가 여기에 있습니다) 직접 메서드 이름을 String 객체로 지정하거나 String 객체를 Selector 유형에 전달해야합니다. 다음은 예입니다.

var rightBarButton = UIBarButtonItem(
    title: "Logout", 
    style: UIBarButtonItemStyle.Plain, 
    target: self, 
    action:"logout"
)

또는

var rightBarButton = UIBarButtonItem(
    title: "Logout", 
    style: UIBarButtonItemStyle.Plain, 
    target: self, 
    action:Selector("logout")
)

Swift 4.1
탭 제스처 샘플 포함

let gestureRecognizer = UITapGestureRecognizer()
self.view.addGestureRecognizer(gestureRecognizer)
gestureRecognizer.addTarget(self, action: #selector(self.dismiss(completion:)))

// Use destination 'Class Name' directly, if you selector (function) is not in same class.
//gestureRecognizer.addTarget(self, action: #selector(DestinationClass.dismiss(completion:)))


@objc func dismiss(completion: (() -> Void)?) {
      self.dismiss(animated: true, completion: completion)
}

자세한 내용은 Apple 문서를 참조하십시오. 선택기 표현식


// for swift 2.2
// version 1
buttton.addTarget(self, action: #selector(ViewController.tappedButton), forControlEvents: .TouchUpInside)
buttton.addTarget(self, action: #selector(ViewController.tappedButton2(_:)), forControlEvents: .TouchUpInside)

// version 2
buttton.addTarget(self, action: #selector(self.tappedButton), forControlEvents: .TouchUpInside)
buttton.addTarget(self, action: #selector(self.tappedButton2(_:)), forControlEvents: .TouchUpInside)

// version 3
buttton.addTarget(self, action: #selector(tappedButton), forControlEvents: .TouchUpInside)
buttton.addTarget(self, action: #selector(tappedButton2(_:)), forControlEvents: .TouchUpInside)

func tappedButton() {
  print("tapped")
}

func tappedButton2(sender: UIButton) {
  print("tapped 2")
}

// swift 3.x
button.addTarget(self, action: #selector(tappedButton(_:)), for: .touchUpInside)

func tappedButton(_ sender: UIButton) {
  // tapped
}

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

func tappedButton(_ sender: UIButton, _ event: UIEvent) {
  // tapped
}

Create Refresh control using Selector method.   
    var refreshCntrl : UIRefreshControl!
    refreshCntrl = UIRefreshControl()
    refreshCntrl.tintColor = UIColor.whiteColor()
    refreshCntrl.attributedTitle = NSAttributedString(string: "Please Wait...")
    refreshCntrl.addTarget(self, action:"refreshControlValueChanged", forControlEvents: UIControlEvents.ValueChanged)
    atableView.addSubview(refreshCntrl)

// 컨트롤 메서드 새로 고침

func refreshControlValueChanged(){
    atableView.reloadData()
    refreshCntrl.endRefreshing()

}

Swift 3.0이 게시되었으므로 targetAction을 적절하게 선언하는 것이 조금 더 미묘합니다.

class MyCustomView : UIView {

    func addTapGestureRecognizer() {

        // the "_" is important
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(MyCustomView.handleTapGesture(_:)))
        tapGestureRecognizer.numberOfTapsRequired = 1
        addGestureRecognizer(tapGestureRecognizer)
    }

    // since Swift 3.0 this "_" in the method implementation is very important to 
    // let the selector understand the targetAction
    func handleTapGesture(_ tapGesture : UITapGestureRecognizer) {

        if tapGesture.state == .ended {
            print("TapGesture detected")
        }
    }
}

사용할 때 performSelector()

/addtarget()/NStimer.scheduledTimerWithInterval() 메서드 (선택자와 일치)를 다음과 같이 표시해야합니다.

@objc
For Swift 2.0:
    {  
        //...
        self.performSelector(“performMethod”, withObject: nil , afterDelay: 0.5)
        //...


    //...
    btnHome.addTarget(self, action: “buttonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
    //...

    //...
     NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector : “timerMethod”, userInfo: nil, repeats: false)
    //...

}

@objc private func performMethod() {
}
@objc private func buttonPressed(sender:UIButton){
….
}
@objc private func timerMethod () {
….
}

For Swift 2.2, you need to write '#selector()' instead of string and selector name so the possibilities of spelling error and crash due to that will not be there anymore. Below is example

self.performSelector(#selector(MyClass.performMethod), withObject: nil , afterDelay: 0.5)

you create the Selector like below.
1.

UIBarButtonItem(
    title: "Some Title",
    style: UIBarButtonItemStyle.Done,
    target: self,
    action: "flatButtonPressed"
)

2.

flatButton.addTarget(self, action: "flatButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)

Take note that the @selector syntax is gone and replaced with a simple String naming the method to call. There’s one area where we can all agree the verbosity got in the way. Of course, if we declared that there is a target method called flatButtonPressed: we better write one:

func flatButtonPressed(sender: AnyObject) {
  NSLog("flatButtonPressed")
}

set the timer:

    var timer = NSTimer.scheduledTimerWithTimeInterval(1.0, 
                    target: self, 
                    selector: Selector("flatButtonPressed"), 
                    userInfo: userInfo, 
                    repeats: true)
    let mainLoop = NSRunLoop.mainRunLoop()  //1
    mainLoop.addTimer(timer, forMode: NSDefaultRunLoopMode) //2 this two line is optinal

In order to be complete, here’s the flatButtonPressed

func flatButtonPressed(timer: NSTimer) {
}

I found many of these answers to be helpful but it wasn't clear how to do this with something that wasn't a button. I was adding a gesture recognizer to a UILabel in swift and struggled so here's what I found worked for me after reading everything above:

let tapRecognizer = UITapGestureRecognizer(
            target: self,
            action: "labelTapped:")

Where the "Selector" was declared as:

func labelTapped(sender: UILabel) { }

Note that it is public and that I am not using the Selector() syntax but it is possible to do this as well.

let tapRecognizer = UITapGestureRecognizer(
            target: self,
            action: Selector("labelTapped:"))

Using #selector will check your code at compile time to make sure the method you want to call actually exists. Even better, if the method doesn’t exist, you’ll get a compile error: Xcode will refuse to build your app, thus banishing to oblivion another possible source of bugs.

override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.rightBarButtonItem =
            UIBarButtonItem(barButtonSystemItem: .Add, target: self,
                            action: #selector(addNewFireflyRefernce))
    }

    func addNewFireflyReference() {
        gratuitousReferences.append("Curse your sudden but inevitable betrayal!")
    }

It may be useful to note where you setup the control that triggers the action matters.

For example, I have found that when setting up a UIBarButtonItem, I had to create the button within viewDidLoad or else I would get an unrecognized selector exception.

override func viewDidLoad() {
    super.viewDidLoad() 

    // add button
    let addButton = UIBarButtonItem(image: UIImage(named: "746-plus-circle.png"), style: UIBarButtonItemStyle.Plain, target: self, action: Selector("addAction:"))
    self.navigationItem.rightBarButtonItem = addButton
}

func addAction(send: AnyObject?) {     
    NSLog("addAction")
}

Change as a simple string naming in the method calling for selector syntax

var timer1 : NSTimer? = nil
timer1= NSTimer(timeInterval: 0.1, target: self, selector: Selector("test"), userInfo: nil, repeats: true)

After that, type func test().


For Swift 3

//Sample code to create timer

Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(updateTimer)), userInfo: nil, repeats: true)

WHERE
timeInterval:- Interval in which timer should fire like 1s, 10s, 100s etc. [Its value is in secs]
target:- function which pointed to class. So here I am pointing to current class.
selector:- function that will execute when timer fires.

func updateTimer(){
    //Implemetation 
} 

repeats:- true/false specifies that timer should call again n again.

Selector in Swift 4:

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

For swift 3

let timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.test), userInfo: nil, repeats: true)

Function declaration In same class:

@objc func test()
{
    // my function
} 

A selector is used to describe the name of a function. Swift doesn’t use selectors, but Objective-C does. And because many iOS frameworks are written in Objective-C, and you use those in conjunction with Swift, you use selectors in Swift.

Before Swift 2.2, you’d use strings as selectors. Like this:

Selector("functionToExecute:")

This has a major disadvantage: you can’t check if a selector is valid during compilation. This often leads to the dreaded unrecognized selector sent to instance error.

So, since Swift 2.2+ you can use the #selector(...) syntax like this:

#selector(functionToExecute(_:))

Don’t forget to add the @objc or @objcMembers[About] attribute to a function that you want to use with target-action.

Quick Tip: Use Xcode’s autocomplete function to get the right function signature. Start typing #selector (and then hit the Esc-key. A dropdown with possible function matches appears. Select the right function, and the right signature is added to your code automatically.

Read more here, here

참고URL : https://stackoverflow.com/questions/24007650/selector-in-swift

반응형