swift - selector() في سويفت؟




nstimer (14)

أيضاً ، إذا لم تنحدر فئة (سويفت) الخاصة بك من فئة Objective-C ، فيجب أن يكون لديك نقطتان في نهاية سلسلة اسم الأسلوب المستهدف ويجب عليك استخدام الخاصيةobjc بالطريقة التي تستهدفها مثل

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

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

وإلا ستحصل على خطأ "Unrecognized Selector" في وقت التشغيل.

أحاول إنشاء 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())

لكن لا شيء يعمل ولا أستطيع إيجاد حل في المراجع.


إذا كنت ترغب في تمرير المعلمة إلى الدالة من 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)
}

قم بتضمين القولون في نص المحدد (اختبار :) ، والمعلمة (المعلمات) الخاصة بك تذهب في userInfo.

يجب أن تأخذ الدالة الخاصة بك NSTimer كمعلمة. ثم فقط استخراج userInfo للحصول على المعلمة التي تم تمريرها.


بالنسبة إلى القراء المستقبليين ، اكتشفت أنني واجهت مشكلة وكنت أتلقى unrecognised selector sent to instance الخطأ التي حدثت بسبب وضع علامة على الدالة func كملف خاص.

يجب أن يكون func مرئيًا بشكل علني ليتم استدعاؤه بواسطة كائن مع الإشارة إلى محدد.


تعتبر المحددات عبارة عن تمثيل داخلي لاسم أسلوب في Objective-C. في Objective-C "selector (methodName)" سيقوم بتحويل طريقة مصدر - برمج إلى نوع بيانات SEL. نظرًا لأنه لا يمكنك استخدام صيغةselector في Swift (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")
)

عند استخدام 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 () {
….
}

بالنسبة لـ Swift 2.2 ، تحتاج إلى كتابة "#selector ()" بدلاً من اسم السلسلة واسم محدد ، لذلك فإن احتمالات الخطأ الإملائي والتعطل بسبب ذلك لن تكون موجودة بعد الآن. أدناه هو سبيل المثال

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

فقط في حالة ما إذا كان لدى شخص آخر نفس المشكلة التي واجهتها مع NSTimer حيث لم يتم حل أي من الإجابات الأخرى المشكلة ، من المهم جدًا الإشارة إلى ذلك ، إذا كنت تستخدم فئة لا ترث من NSObject إما بشكل مباشر أو عميق في التسلسل الهرمي ( على سبيل المثال ملفات swift تم إنشاؤها يدويًا) ، لن تعمل أي من الإجابات الأخرى حتى عند تحديدها على النحو التالي:

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

دون تغيير أي شيء آخر غير مجرد ترث الطبقة من NSObject توقفت عن الحصول على خطأ "Unrecognized selector" وحصلت على منطق عملي كما هو متوقع.


قد يكون من المفيد ملاحظة المكان الذي تقوم فيه بإعداد عنصر التحكم الذي يشغل مسائل الإجراء.

على سبيل المثال ، لقد وجدت أنه عند إعداد UIBarButtonItem ، اضطررت إلى إنشاء الزر داخل viewDidLoad وإلا فإنني سأحصل على استثناء محدد غير محدد.

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")
    }

قمت بإنشاء محدد مثل أدناه.
1.

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

2.

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

لاحظ أن صيغةselector اختفت واستبدلت بسلسلة بسيطة لتسمية طريقة الاتصال. هناك مجال واحد يمكننا أن نتفق جميعًا على أن الإسهال حصل فيه. بالطبع ، إذا أعلنا أن هناك طريقة مستهدفة تسمى flatButtonPressed: فنحن نفضل كتابة واحد:

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

ضبط المؤقت:

    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

لكي تكون كاملًا ، إليك هنا flatButtonPressed

func flatButtonPressed(timer: NSTimer) {
}

لقد وجدت أن العديد من هذه الإجابات مفيدة ولكن لم يكن من الواضح كيفية القيام بذلك باستخدام شيء لم يكن زرًا. كنت أقوم بإضافة أداة التعرف على الإيماءات إلى UILabel بسرعة وكفاح حتى هنا ما وجدته عملت لي بعد قراءة كل شيء أعلاه:

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

حيث تم الإعلان عن "Selector" على النحو التالي:

func labelTapped(sender: UILabel) { }

لاحظ أنه عام وأنني لا أستخدم صيغة Selector () ولكن من الممكن القيام بذلك أيضًا.

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

منذ نشر 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")
        }
    }
}

سويفت 4.0

قمت بإنشاء محدد مثل أدناه.

1. إضافة الحدث إلى زر مثل:

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

وستكون الوظيفة كما يلي:

@objc func clickedButton(sender: AnyObject) {

}

سويفت 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 للحصول على مزيد من التفاصيل حول: Selector Expression


// 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()

}




nstimer