Swift 4'te #selector () ile @objc çıkarımının kullanımdan kaldırılmasıyla nasıl başa çıkabilirim?


131

Projemin kaynak kodunu Swift 3'ten Swift 4'e dönüştürmeye çalışıyorum. Xcode'un bana verdiği bir uyarı seçicilerimle ilgili.

Örneğin, normal bir seçici kullanarak bir düğmeye bir hedef ekliyorum:

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

Gösterdiği uyarı şu şekildedir:

"#Selector" argümanı, Swift 4'te kullanımdan kaldırılan "@objc" özniteliğine bağlı olan "ViewController" içindeki "myAction ()" örnek yöntemini ifade eder

Bu örnek yöntemini Objective-C'ye sunmak için '@objc' ekleyin

Şimdi, Fixhata mesajına basmak bunu benim işlevime yapar:

// before
func myAction() { /* ... */ }

// after
@objc func myAction() { /* ... */ }

Tüm işlevlerimi @objcişareti içerecek şekilde yeniden adlandırmak istemiyorum ve bunun gerekli olmadığını varsayıyorum.

Kullanımdan kaldırmayla başa çıkmak için seçiciyi nasıl yeniden yazarım?


İlgili soru:


3
Hayır, onları Obj-C'ye maruz bırakmak ve bu nedenle seçicilerle kullanmak @objc için artık gerekli olarak işaretlemek .
Hamish

3
Öyleyse, kullanımdan kaldırılan kısım, genel erişim işlevlerini @objc? Bu biraz can sıkıcı, ancak genellikle bu işlevleri özel hale getiriyorum ve yine de işaretlememi gerektiriyor @objc.
Connor

2
Değişiklik hakkında daha fazla bilgi için SE-0160'a bakın . Diğer bir alternatif, @objcMemberstüm Obj-C uyumlu üyeleri Obj-C'ye maruz bırakmak için verilen sınıfınızı işaretlemektir , ancak tüm sınıfınızın açığa çıkmasına gerçekten ihtiyacınız olmadığı sürece bunu tavsiye etmem.
Hamish

3
@LinusGeffarth Teklifte belirtildiği gibi, ikili programınızın boyutunu gereksiz yere artırabilir ve dinamik bağlantınız daha uzun sürecektir. Obj-C'den kullanılacak belirli bir şeyin özellikle kastettiğin ilave netlik için gerçekten çok fazla güçlük olduğunu düşünmüyorum.
Hamish

1
Denedim, çalışmıyor.
LinusGeffarth

Yanıtlar:


156

Düzeltme doğrudur - başvurduğu yöntemi Objective-C'ye maruz bırakmak için seçici hakkında değiştirebileceğiniz hiçbir şey yoktur.

İlk etapta bu uyarının tüm nedeni SE-0160'ın sonucudur . Swift 4'ten önce internalveya daha yüksek Objective-C uyumlu NSObjectmirasçı sınıfların üyelerinin Objective-C'ye @objcmaruz kaldığı ve dolayısıyla onlara maruz kaldıkları çıkarıldı , bu nedenle seçiciler kullanılarak çağrılmalarına izin verildi (çünkü yöntemi aramak için Obj-C çalışma zamanı gerekliydi) belirli bir seçici için uygulama).

Ancak Swift 4'te artık durum böyle değil. Sadece çok özel açıklamalar şimdi olmak çıkarılmaktadır @objcörneğin, bir geçersiz kılmaları @objcyöntemlerinin uygulamaları @objcima özelliklerle protokol şartları ve bildirimleri @objcgibi @IBOutlet.

Bunun arkasındaki motivasyon , yukarıdaki bağlantılı öneride detaylandırıldığı gibi , ilk olarak, NSObjectsınıfların miras alınmasındaki aşırı metot aşırı yüklerinin, özdeş seçicilere sahip oldukları için birbirleriyle çarpışmasını önlemektir . İkinci olarak, Obj-C'ye maruz kalması gerekmeyen üyeler için thunk oluşturmak zorunda kalmayarak ikili boyutu azaltmaya yardımcı olur ve üçüncü olarak dinamik bağlamanın hızını artırır.

Bir üyeyi Obj-C'ye maruz bırakmak istiyorsanız @objc, örneğin şu şekilde işaretlemeniz gerekir :

class ViewController: UIViewController {

    @IBOutlet weak var button: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        button.addTarget(self, action: #selector(foo), for: .touchUpInside)
    }

    @objc func foo() {
       // ... 
    }
}

("çıkarımı en aza indir" seçeneği seçiliyken, göçmen bunu seçicilerle sizin için otomatik olarak yapmalıdır)

Bir grup üyeyi Obj-C'ye maruz bırakmak için şunları kullanabilirsiniz @objc extension:

@objc extension ViewController {

    // both exposed to Obj-C
    func foo() {}
    func bar() {}
}

Bu, içinde tanımlanan tüm üyeleri Obj-C'ye maruz bırakır ve Obj-C'ye maruz kalamayan herhangi bir üyede bir hata verir (açıkça işaretlenmedikçe @nonobjc).

İhtiyacınız bir sınıf varsa hepsi Obj-C uyumlu üyeleri Obj C maruz kalması, sınıfı olarak işaretleyebilirsiniz @objcMembers:

@objcMembers
class ViewController: UIViewController {
   // ...
}

Şimdi, olduğu anlaşılabilecek tüm üyeler @objcolacak. Ancak, üyelerin gereksiz yere açığa çıkmasının yukarıda belirtilen dezavantajları göz önüne alındığında, Obj-C'ye maruz kalan tüm üyelere gerçekten ihtiyaç duymadığınız sürece bunu yapmanızı tavsiye etmem .


2
Xcode, kodu en son sözdizimine dönüştürürken neden bunu otomatik olarak yapmıyor?
LinusGeffarth

1
Merak ediyorum @IBActionda otomatik olarak @objcmı? şimdiye kadar durum böyle değildi ama mantıklı olurdu. DÜZENLEME: nvm, teklif @IBActionbir yöntemin olması için yeterli olduğunu açıkça belirtiyor @objc.
Sulthan

8
Ben bunların hiçbirini anlamıyorum. Hiç bir Amaç-C kodum yok. Bir düğmeye hedef eklemenin saf Swift yolu yok mu? Veya seçicileri mi kullanıyorsunuz? Kodumun bu öznitelikle delinmesini istemiyorum. Bir UIB düğmesinin bazı NSObject / Obj-c-şeyinden türetilmesi nedeniyle mi?
Sti

11
@Sti Yani doğrudan " Bir düğmeye hedef eklemenin saf Swift-yolu yok mu? Ya da seçiciler kullanılıyor mu? " - hayır, yöntemlere göndermek için seçicileri kullanmanın "saf Swift" yolu yoktur. Belirli bir seçiciyi aramak için yöntem uygulamasını aramak için Obj-C çalışma zamanına güvenirler - Swift çalışma zamanı bu özelliğe sahip değildir.
Hamish

12
Erkek seçiciler tam bir karmaşa. Görünüşe göre diğer hızlı güncellemelerle uğraşıyorlar. Neden yöntemler için tamamen hızlı bir otomatik tamamlama seçiciye sahip olamıyoruz? Kodu çok çirkin gösteriyor.
John Riselvato

16

As Apple Resmi Belgeler . Selector Method'unuzu çağırmak için @objc kullanmanız gerekir.

Objective-C'de, bir seçici, bir Objective-C yönteminin adını ifade eden bir türdür. Swift'de Objective-C seçicileri Selectoryapı tarafından temsil edilir ve #selector ifade kullanılarak oluşturulabilir . Objective-C'den çağrılabilen bir yöntem için bir seçici oluşturmak için, yöntemin adını, örneğin #selector(MyViewController.tappedButton(sender:)). Bir özelliğin Objective-C alıcı veya ayarlayıcı yöntemi için bir seçici oluşturmak için, getter:veya setter:etiketi ile önek olarak, örneğin #selector(getter: MyViewController.myButton).


Bundan anladığım tek şey, bazı durumlarda onu Objective-C'den arayacak olsam da çağırmasam da bir işlevin başlangıcına @objc eklemem gerektiğidir. Swift'i yıllarca Obj-C kullanarak
öğreniyorum

10

Bence Swift 4.2, tek yapmanız gereken yönteminize @IBAction atamak ve bu aptalca @objc açıklamasından kaçınabilirsiniz.

`

let tap  =  UITapGestureRecognizer(target: self, action: #selector(self.cancel))


@IBAction func cancel()
{
    self.dismiss(animated: true, completion: nil)
}

1
Bu aynı zamanda arayüz oluşturucuya bu işlevin bağlanabileceğini söyleyecektir, ki bu sizin istediğiniz şey olmayabilir. Ayrıca @objc ile aynı şeyi yapıyor.
Josh Paradroid

2

Diğer yanıtlarda da belirtildiği gibi, @objcseçiciler için ek açıklamadan kaçınmanın bir yolu yoktur .

Ancak OP'de bahsedilen uyarı, aşağıdaki adımlar atılarak susturulabilir:

  1. Yapı Ayarlarına Git
  2. @Objc anahtar kelimesini ara
  3. Değerini ayarlama Swift 3 @objc arayüzü içinOff

Aşağıda, yukarıda belirtilen adımları gösteren ekran görüntüsü yer almaktadır:

"Swift 3 @objc arayüzü" uyarısını susturma

Bu yardımcı olur umarım


Bu, büyük resimde projenizi nasıl etkiler?
Zonily Jame

1
Peki ya * .ipa veya * .xarchive boyutuna ve derleme süresine ne dersiniz?
Zonily Jame

@ZonilyJame, derleme zamanını fark etmedim, ancak IPA boyutunda bir etkisi
olmadı

Bu, Apple yönergelerine göre hızlı 4.0+ sürümünü kullanıyorsanız kullanabileceğiniz tavsiye edilen bir değer değildir. Bu help.apple.com/xcode/mac/current/#/deve838b19a1
Bhavin_m

1
Xcode 11'de değeri Varsayılan olarak ayarlayarak bu yanıtı güncelleyebilirsiniz. Uyarıyı tamamen kaldırmak için değeri hem proje hem de hedeflerinize ayarlamak önemlidir.
Tommie C.

2

Görünüm denetleyicinizde nesnel c üyelerine ihtiyacınız varsa, yalnızca görüntüleme denetleyicisinin üst kısmına @objcMembers ekleyin . Ve kodunuza IBAction ekleyerek bundan kaçınabilirsiniz.

@IBAction func buttonAction() {

}

Bu prizi film şeridine bağladığınızdan emin olun.

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.