Derleyici hatası: Objective-C seçicili yöntem, aynı Objective-C seçicisiyle önceki bildirimle çakışıyor


209

Swift'i öğrenmeye başladım ve YouTube'daki çok iyi Stanford Üniversitesi video derslerini takip ediyorum. İlgileniyorsanız veya yardımcı olursa bir bağlantı (sorunumu anlamanız gerekmese de):

Swift ile iOS 8 Uygulamaları Geliştirme - 2. Daha Fazla Xcode ve Swift, MVC

Dersleri takip ederken (anlayabildiğim kadarıyla) kodumun videodaki kodla aynı olduğu bir noktaya geldim ama sistemimde bir derleyici hatası aldım. Deneme ve hata bir sürü sonra kodumu biri hata üretir, diğeri oluşturur ya da değil, iki örneğe azaltmayı başardık, ama aslında ne hataya neden veya nasıl çözmek için hiçbir fikrim yok.

Hatayı oluşturan kod:

import UIKit

class BugViewController: UIViewController
{
    func perform(operation: (Double) -> Double) {
    }

    func perform(operation: (Double, Double) -> Double) {
    }
}

Bu, aşağıdaki derleyici hatasını oluşturur:

Objective-C seçicisiyle 'perform' yöntemi 'perform:' aynı Objective-C seçicisiyle önceki bildirimle çakışıyor

Sadece UIViewController alt sınıfını kaldırarak kod derler:

import UIKit

class BugViewController
{
    func perform(operation: (Double) -> Double) {
    }

    func perform(operation: (Double, Double) -> Double) {
    }
}

Alakalı olabilecek veya olmayabilecek diğer bazı bilgiler:

  • Geçenlerde Yosemite'e geçtim.
  • Xcode'u yüklediğimde, bir Beta sürümü (Sürüm 6.3 (6D543q)) ile sonlandım çünkü (doğru hatırlarsam) bu, OS X sürümümde çalıştırmam gereken sürümdü.

Yarısının bu derleyicide bir hata olduğunu umuyorum çünkü aksi halde bu benim için bir anlam ifade etmiyor. Herhangi bir yardım çok minnetle aldı!


3
Xcode 6.2'yi Yosemite üzerinde çalıştırabilirsiniz. Uygulama mağazasından indirebilir ve Beta sürümü ile sisteminizde yaşayabilir. Bu noktada Stanford sınıfı için Xcode 6.3 kullanmanızı tavsiye etmem çünkü beta ve Swift'in önceki sürümünün videolarda kullandığı durumdan farklı olan Swift 1.2'yi içeriyor.
vacawama

2
5 Nisan'dan (feb) kullanıcısının (şu anda kabul edilen) yanıtı artık en iyisi değil. Bunun yerine (16 Nisan) (James Zhang) cevabı daha spesifik ve doğrudur.
phlebotinum

Yanıtlar:


144

Objective-C yöntem aşırı yüklemeyi desteklemiyor, farklı bir yöntem adı kullanmanız gerekiyor. UIViewController'ı miras aldığınızda NSObject'i miras aldınız ve sınıfı Obj-C ile birlikte çalışabilir hale getirdiniz. Swift ise aşırı yüklemeyi destekliyor, bu yüzden miras kaldırdığınızda çalışıyor.


2
Objective-C SUPPORTS yöntemini geçersiz kılma (zaten bastırılmış bir şeyi aşırı yüklemeyle ilgili sizi bilgilendiren bir (bastırılabilir) derleyici uyarıları ile), Apple sadece çerçevelerini aşırı yüklenmekten uzak tutmak için bunu yapmanızı istemez. Bu tür aşırı yükleri UIFonther gün kullanıyorum.
Michi

@ polarwar'ın cevabı aşağıdaki Swift 2 için en iyisidir: stackoverflow.com/a/31500740/144088
Crashalot

237

Ben de Standford kursuna katılıyorum ve burada da uzun süre kaldım, ama bazı aramalardan sonra, buradan bir şey buldum: Xcode sürüm notları ve aşağıda bir şeyden bahsetti:

Swift 1.2, Objective-C tarafından desteklenmeyen bir şey olan @objc yöntemlerinin ve başlatıcıların tip tabanlı aşırı yüklenmesini kontrol etmede katıdır.

// Has the Objective-C selector "performOperation:".
func performOperation(op: NSOperation) { /* do something */ }
// Also has the selector "performOperation:".
func performOperation(fn: () -> Void) {
    self.performOperation(NSBlockOperation(block: fn))
}

Bu kod Swift'ten çağrıldığında işe yarar, ancak Objective-C çağrıldığında kolayca çökebilir. Bu sorunu çözmek için, Swift derleyicisinin üyeyi Objective-C çalışma zamanına maruz bırakmasını önlemek için Objective-C tarafından desteklenmeyen bir tür kullanın:

  • Mantıklıysa @objc çıkarımını devre dışı bırakmak için üyeyi özel olarak işaretleyin.
  • Aksi takdirde, varsayılan değeri olan bir kukla parametre kullanın, örneğin: _ nonobjc: () = (). (19826275)

Özel alt sınıflarda Objective-C'ye maruz bırakılan yöntemlerin geçersiz kılmaları @objc olarak çıkmaz ve Swift derleyicisinin çökmesine neden olur. @Objc niteliğini bu tür geçersiz kılma yöntemlerine açıkça ekleyin. (19935352)

Swift kullanan bir projede veya çalışma alanında Hızlı Aç seçeneğini kullanırken SDK'lardan gelen semboller kullanılamaz. (20349540)

ne yaptım sadece böyle geçersiz kılma yönteminin önünde "özel" ekliyordu:

    private func performOperation(operation: Double -> Double) {
    if operandStack.count >= 1 {
        displayValue = operation(operandStack.removeLast())
        enter()
    }
}

3
Bu çözüm
imho bulduğum

38
Artık bir yöntemi Objective-C çalışma zamanından hariç tutmak için kullanılabilecek bir @nonobjc özniteliği de bulunduğunu lütfen unutmayın.
Erik J

2
ErikJ'in yorumunu ve aşağıda polarwar'ın cevabını @. Bu, Swift 2 ve xcode 7 ile ilerlemek için en iyi yanıt gibi görünüyor. Henüz güncellemediyseniz, kesinlikle tavsiye ederim.
Austin A

@ polarwar'ın cevabı aşağıdaki Swift 2 için en iyisidir: stackoverflow.com/a/31500740/144088
Crashalot

111

Daha önce yanıtlandığı için, ObjC yöntem aşırı yüklemesini desteklemiyor (aynı ada sahip iki yöntem) ve Xcode 7 altında hızlı 2'de bu tür sorunları çözmek için iki seçenek var. Seçeneklerden biri yöntemi şu özniteliği kullanarak yeniden adlandırmaktır:@objc(newNameMethod:)

func methodOne(par1, par2) {...}

@objc(methodTwo:)
func methodOne(par1) {...}

Xcode 7 ve sonraki sürümlerinde bu sorunu çözmek için başka bir seçenek, @nonobjcherhangi bir yönteme, aboneliğe veya başlatıcıya öznitelik uygulamaktır

func methodOne() {...}

@nonobjc
func methodOne() {...}

6
bu, hızlı 2 (ve üstü) sorununu çözer. en doğru cevap olarak güncellenmelidir. Ty.
Maxim Veksler

2
Swift 2 ve Xcode 7 + kullanan herkes için bu, polarwar'a katılıyorum
TerNovi

17

Sorun UIViewControllerbir @objcsınıf. Devralınırken UIViewController, BugViewControlleraynı zamanda bir @objcsınıftır.

Bu, Objective-C seçicilerinin (bir yöntemin adı) kurallarına uyması gerektiği anlamına gelir. Yöntemler func perform(operation: (Double) -> Double)ve func perform(operation: (Double, Double) -> Double)her ikisi de aynı seçiciye sahiptir @selector(perform:). Buna izin verilmiyor.

Bu sorunu çözmek için farklı adlar kullanın: like func perform1(operation: (Double) -> Double)ve func perform2(operation: (Double, Double) -> Double).


Bunun üstesinden gelmenin en iyi yolunun perform()yöntemlerinize daha açıklayıcı isimler vermektir . Bu yöntemler ne işe yarar? Görünüm denetleyicisinin durumunu nasıl değiştiriyorlar? UIViewControllerYöntem adlandırma stili hakkında fikir edinmek için diğer yöntemlere bakın veya Yöntem Adlarının Sınıf İçinde Etkileyici ve Benzersiz Olması gerektiğini okuyun.


Teşekkürler - bu sorumu mükemmel bir şekilde cevaplıyor ve ilk siz olduğunuzda bunu doğru olarak işaretleyeceğim.
Auspice

Hala derleme kodumun ne yaptığını eminim ben hala ders kodu neden işe yaramadı anlamıyorum! Hey ho - Geri dönüp tekrar kontrol edeceğim. Farklı bir şey olmalı.
Ağustos

2
@Auspice Videolar için kullandıkları Xcode sürümü ile hatalar üretmemiş olabilir, ancak yine de bir sorundu. Derleyici Xcode 6.3'e kadar sizi uyarabilmişti.
Mick MacCallum

3
Paul Hegarty burada 'aşırı yükleme' işlevini göstermek istiyor (aynı isimle, ancak farklı argümanlar kümesiyle 2 işlev), bu yüzden aynı yöntem adını bilerek kullanıyor! Aşırı yüklemeye yalnızca Swift'te izin verilir, Objective-C'de izin verilmez. Bu nedenle çözüm, UIViewController (bu bir Objective-C sınıfı olan) miras formunu kaldırmak veya yöntemi özel olarak bildirmektir. Her iki çözüm de buradaki diğer cevaplarda ayrıntılı olarak açıklanmaktadır.
Ronny Webers

Aslında fonksiyonun önünde özel anahtar kelime kullandım. like, private func performOperation (çalışma: Çift -> Çift) {} ve özel func performOperation (çalışma: (Çift, Çift) -> Çift) {} Burada PRIVATE yardımı ile aşırı yükleme yöntemine ulaştım. çünkü her ikisini de yalnızca ViewController.Swift'te kullandım. Derleyici neden herhangi bir hata söylemiyor?
iTag


2

Aynı Obj-C imzası ile iki yöntem olması nedeniyle aynı hatayı aldım:

static func prepareForUpSyncing(obj : NSManagedObject!) -> Bool
static func prepareForUpSyncing(objs : [NSManagedObject]!) -> Bool

Çalışma zamanında öngörülemeyen sonuçlar olasılığı nedeniyle bunlardan birini @nonobjc olarak işaretlemek istemedim. (Bir ihtimal yoksa biri beni düzeltebilir)

Swift'in harici parametre adı özelliğini (yerel adla aynı harici adı yaptım) kullanarak Obj-c yöntemi imzasını etkili bir şekilde değiştiren ikinci yönteme çözümlendi:

static func prepareForUpSyncing(objs objs : [NSManagedObject]!) -> Bool {
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.