Yanıtların Swift eşdeğeri nedir?


195

Google'ı aradım, ancak hızlı eşdeğerin ne olduğunu bulamadım respondsToSelector:.

Bu bulabildiğim tek şey ( yanıtlara Swift alternatifi:) ama benim durumumda temsilci varlığını kontrol ettiği için çok alakalı değil, sadece yeni bir API olup olmadığını kontrol etmek istediğim bir temsilci yok cihazda çalışırken veya değil ise API'nin önceki bir sürümüne geri dönmez.


Bunların tümü Opsiyonellerle değiştirilmeli ve İsteğe Bağlı Zincirleme ile kullanılmalıdır
Jack

Apple'ın yeni uygulanmış işlevselliği kontrol etmek için açıkça NSClassFromStringve respondsToSelectordiğer mekaniklerin kullanılmasını önerdiği göz önüne alındığında , mekanizmaların zaten mevcut olduğuna veya yayınlanmadan önce orada olacağına inanmalıyım. Advanced Interop...WWDC'den video izlemeyi deneyin .
David Berry

2
@Jack Wu Peki ya yeni yöntem UIApplication veya UIViewController gibi temel bir şeye sunulan yeni bir şeyse. Bu nesneler isteğe bağlı değildir ve yeni yöntem isteğe bağlı değildir. Örneğin UIApplcation: newVersionOfMethodX'i çağırmanız veya UIApplication: deprecatedVersionOfMethodX'i çağırmanız gerekip gerekmediğini nasıl kontrol edebilirsiniz? (
İOS

İlgilendiğiniz / ilgilendiğiniz API bir Apple API'sı mı?
GoZoner

@PotassiumPermanganate - tabii ki, eğer cevap 'evet, Apple API'lerini kullanıyordum, belki de ilk etapta if #available(...)kullanmaktan kaçınmak için Swift 2.x'de kullanabilir respondsToSelector. Ama biliyordun. ( apple.co/1SNGtMQ )
GoZoner

Yanıtlar:


170

Belirtildiği gibi, Swift'te çoğu zaman ?isteğe bağlı paket çıkarıcı operatör ile ihtiyacınız olanı elde edebilirsiniz . Bu, yalnızca nesne varsa (yoksa nil) ve yöntem uygulandığında bir nesne üzerindeki yöntemi çağırmanıza olanak tanır .

Hâlâ ihtiyaç duyduğunuz durumda respondsToSelector:, hala oradaNSObject protokolün bir .

Aradığınız Eğer respondsToSelector:Swift bir Obj-C tipine, o zaman beklediğiniz gibi çalışır. Kendi Swift sınıfınızda kullanıyorsanız, sınıfınızın türetildiğinden emin olmanız gerekir NSObject.

Aşağıda, bir seçiciye yanıt verip vermediğini kontrol edebileceğiniz bir Swift sınıfı örneği:

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

Parametre adlarını dışarıda bırakmamanız önemlidir. Bu örnekte, Selector("sleep::")ile aynı değildirSelector("sleep:minutes:") .


UIApplication için iOS8'de tanıtılan yeni bir yöntemin var olup olmadığını belirlemeye çalışıyorum ve şimdiye kadar hiç şansım yok. Yukarıdakilere göre nasıl çalışıyorum: if present = UIApplication.sharedApplication (). YanıtlarToSelector (Selector ("redactedAsStillUnderNDA")). Ancak bir derleme hatası alıyorum: "Koşullu bağlamada bağlı değer isteğe bağlı tür olmalıdır".
Gruntcakes

4
Bu çizgileri ayırmanız veyalet x = bölümü kaldırmanız gerekir . Temel olarak, if let x = yyapı isteğe bağlı değerleri açmaktır (benzer !). Bir alıyorsanız bu yana Boolgelen geri respondsToSelector, derleyici sonuç isteğe bağlı bir tip olmadığını şikayet ediyor ( Bool?).
Erik

varBildirilenlere ne olur ? Hala aynı şekilde mi cevap veriyorlar? Objective-C'de if ( [obj respondsToSelector:@selector(setSomeVar:)] ) { ... }bir someVarmülk için yapabilirim . varSwift'teki s ile aynı şekilde çalışıyor mu ?
Alejandro Iván

İsteğe bağlı Görünüm denetleyicisi örneğini sıfır değilse, ancak yöntem veya işlev bu denetleyiciye uygulanmazsa ne olur? Sanırım nesnenin seçiciye yanıt verip vermediğini kontrol etmeniz gerekecek.
Ashish Pisey

Ben "Değer türündeki 'UIViewController' hayır üyesini 'respondsToSelector' vardır" alıyorum
Michal Ziobro

59

Gerçek Swift yedeklemesi yok.

Aşağıdaki şekilde kontrol edebilirsiniz:

someObject.someMethod?()

Bu, yöntemi someMethodyalnızca nesne üzerinde tanımlanmışsa çağırır, someObjectancak yalnızca @objcyöntemi olarak bildiren protokoller için kullanabilirsiniz optional.

Swift doğası gereği güvenli bir dildir, bu yüzden her yöntem çağırdığınızda Swift, yöntemin orada olduğunu bilmelidir. Çalışma zamanı kontrolü mümkün değildir. Rasgele nesneler üzerinde rastgele yöntemler çağıramazsınız.

Obj-C'de bile mümkün olduğunca bu tür şeylerden kaçınmalısınız çünkü ARC ile iyi oynamaz (ARC daha sonra için uyarıları tetikler performSelector:).

Bununla birlikte, kullanılabilir API'ları kontrol ederken respondsToSelector:, Swift ile bile olsa, NSObjectörneklerle uğraşıyorsanız da kullanabilirsiniz :

@interface TestA : NSObject

- (void)someMethod;

@end

@implementation TestA

//this triggers a warning

@end   


var a = TestA()

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

1
Bu nedenle uygulamalar artık hangi işletim sistemi üzerinde çalıştıklarını açıkça bilmelidir? Yalnızca iOS8'de bulunan bir yöntemi çağırmak istiyorum ve yoksa eski iOS7 sürümünü kullanın. Yani yeni yöntemin varlığını / yokluğunu kontrol etmek yerine bunun yerine iOS8'de olup olmadığımı öğrenmek zorundayım. Swift iyi ama bu biraz hantal görünüyor.
Gruntcakes

@sulthan respondsToSelector:Apple'ın tavsiyesi açıkça yapmanız gerektiği için kullanmamanız gerektiğini belirttiğinizden emin değilim . Buraya
David Berry

@David Evet, respondsToSelector:aslında iyi olan birkaç durumdan birini buldunuz . Ancak Swift referansından geçerseniz, farklı sistem sürümleri için alt sınıfların kullanılması hakkında konuşurlar.
Sulthan

OP'nin konuştuğu durum bu değilse ve isteğe bağlı protokol vakası hakkında konuşuyorlarsa, isteğe bağlı zincirleme (buna işaret ettiğiniz gibi) kullanılmasına da açıkça izin verirler. Her iki durumda da, "Apple'ın size açıkça yapmasını söylediklerini yapmaktan kaçınmalısınız" demek kötü bir tavsiye gibi görünüyor. Apple, çalışma zamanında isteğe bağlı işlevleri belirlemek ve uygulamak için "her zaman" mekanizmalar sağlamıştır.
David Berry

1
@Honey Swift'te genellikle kullanılabilirlik yönergelerini kullanırız, örneğin if #available(iOS 10) {yöntemi doğrudan çağırırız.
Sulthan

40

Swift 3 sözdizimi için 20 Mart 2017'yi güncelleyin:

İsteğe bağlı yöntemin var olup olmadığını umursamıyorsanız, yalnızca delegate?.optionalMethod?()

Aksi takdirde, kullanmak guardmuhtemelen en iyi yaklaşımdır:

weak var delegate: SomeDelegateWithOptionals?

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

Orijinal cevap:

Bunun gibi isteğe bağlı bir protokolü test etmek için "if let" yaklaşımını kullanabilirsiniz:

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 = delege edilsin mi? .theOptionalProtocolMethod
john07

1
Birden fazla aday olduğunda seçici sözdizimi örneği:let theMethod = delegate.userNotificationCenter(_:willPresent:withCompletionHandler:)
Cœur

11

Protokolünüzü NSObjectProtocol alt protokolü olarak tanımlamanız gerektiği anlaşılıyor ... o zaman yanıtlar alacaksınızSelector yöntemi

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

yalnızca @objc belirtmenin yeterli olmadığını unutmayın. Ayrıca, gerçek delegenin NSObject'in bir alt sınıfı olduğuna da dikkat etmelisiniz - Swift'te olmayabilir.


10

Test ettiğiniz yöntem bir @objc protokolünde isteğe bağlı bir yöntem olarak tanımlanmışsa (durumunuz gibi görünür), isteğe bağlı zincirleme desenini şu şekilde kullanın:

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

Yöntem dönen olarak bildirildiğinde Void, şunu kullanın:

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

Görmek:

“İsteğe Bağlı Zincirleme Yoluyla Arama Yöntemleri”
Alıntı: Apple Inc. “Hızlı Programlama Dili.”
iBooks. https://itun.es/us/jEUH0.l


Bu sadece yöntem bir şey döndürürse işe yarar, ya geçersiz bir yöntemse?
Gruntcakes

1
Sadece boşluk kullanımı ise if object.method?(args) { ... }- yöntemin çağrı, geçerli olduğu hallerde, dönecektir Voidolmadığınil
GoZoner

1
Ancak "Tip Boşluğu" Mantık Değeri "protokolüne uymuyor
Gruntcakes

Lütfen başvurulan belgelere bakın (sayfa 311-312).
GoZoner

"Test ettiğiniz yöntem bir @objc protokolünde isteğe bağlı bir yöntem olarak tanımlanmışsa" Veya objecttürü varsa , AnyObjectherhangi bir @objc yöntemini test edebilirsiniz.
Newacct

9

İşlevler Swift'teki birinci sınıf türleridir, bu nedenle bir protokolde tanımlanan isteğe bağlı bir işlevin nil ile karşılaştırılarak uygulanıp uygulanmadığını kontrol edebilirsiniz:

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

1
Yöntem aşırı yüklenmişse ne olur? Belirli bir tanesini nasıl kontrol edebiliriz?
Nuno Gonçalves

8

Swift3 için

Sadece yöntemi çağırmak istiyorsanız, aşağıdaki kodu çalıştırın.

self.delegate?.method?()


7

Swift 2, Apple denilen yeni bir özellik tanıttı API availability checkingyerini olabilir, respondsToSelector:WWDC2015 Oturum 106 kopyalanır kod parçacığı karşılaştırma aşağıdaki method.The Swift Yenilikler sana yardım düşündüm eğer gerekiyorsa, bunu kontrol edin daha fazla bilgi.

Eski Yaklaşım:

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

Daha İyi Bir Yaklaşım:

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

Bence bu respondsToSelector, Swift'teki yaklaşımı kullanmaktan çok daha iyi bir çözüm . Bunun nedeni ayrıca, seçici kontrolün bu soruna (kullanılabilirlik kontrolü) en iyi çözüm olmamasıdır.
JanApotheker

6

Hızlı 3.0 için

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

Şu anda (Swift 2.1) 3 yolu kullanarak kontrol edebilirsiniz:

  1. AnswersToSelector kullanma @Erik_at_Digit tarafından cevap
  2. Kullanılması '?' Tarafından cevap @Sulthan

  3. Ve as?operatör kullanarak :

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

Temelde neyi başarmaya çalıştığınıza bağlıdır:

  • Örneğin, uygulama mantığınızın bir eylem gerçekleştirmesi gerekiyorsa ve temsilci ayarlanmadıysa veya sivri temsilci onSuccess () yöntemini (protokol yöntemi) uygulamadıysa, bu yüzden kullansam da seçenek 1 ve 3 en iyi seçimdir Swift yolu olan seçenek 3.
  • Temsilci sıfır veya yöntem uygulanmadığında hiçbir şey yapmak istemiyorsanız 2. seçeneği kullanın.

2

Sadece kendimi bir projede uyguluyorum, aşağıdaki koda bakınız. @Christopher Pickslay'den bahsedildiği gibi, işlevlerin birinci sınıf vatandaş olduğunu ve bu nedenle isteğe bağlı değişkenler gibi davranılabileceğini hatırlamak önemlidir.

@objc protocol ContactDetailsDelegate: class {

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

...

weak var delegate:ContactDetailsDelegate!

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

Yöntem aşırı yüklenmişse ne olur? Bunu nasıl yaparsınız?
Nuno Gonçalves

2

hızlı bir şekilde başka bir sözdizimi.

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

2

Eski projemi Swift 3.2 olarak güncellemeye başladığımda, yöntemi

respondsToSelector(selector)

için:

responds(to: selector)

0

Kullandığım guard let elsetemsilci fonk uygulanmadığı taktirde bazı varsayılan şeyler yapabilirim yüzden.

@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

Hızlı 3:

protokol

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

Nesne

class SomeObject : NSObject {

weak var delegate:SomeObject?

func delegateMethod() {

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

   }

}

-4

Eşdeğerdir? Şebeke:

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

importantMethod yalnızca myQuestionableObject varsa ve uygularsa çağrılacaktır.


Ancak, myQuestionalObject, UIApplication (bu nedenle var olacak ve dolayısıyla varlığını kontrol etmek anlamsız) gibi bir şeyse ve importandMethod (), iOS N'de tanıtılan yeni bir yöntemdir ve onu arayabileceğinizi mi yoksa N-1'de eski deprecatedImportantMethod ()?
Gruntcakes

2
ayrıca bir ?sonraya ihtiyacım varimportantMethod
newacct
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.