'Bildirilmemiş seçici' uyarısından nasıl kurtulurum


162

Uygulanan bir protokole gerek olmadan bir NSObject örneği üzerinde bir seçici kullanmak istiyorum . Örneğin, çağrıldığı NSObject örneği bunu destekliyorsa, bir hata özelliği ayarlaması gereken bir kategori yöntemi vardır. Bu koddur ve kod istendiği gibi çalışır:

if ([self respondsToSelector:@selector(setError:)])
{
    [self performSelector:@selector(setError:) withObject:[NSError errorWithDomain:@"SomeDomain" code:1 userInfo:nil]];
}

Ancak, derleyici setError: imza ile bir yöntem görmez, bu yüzden @selector(setError:)snippet'i içeren her satır için bana bir uyarı verir :

Undeclared selector 'setError:'

Bu uyarıdan kurtulmak için bir protokol bildirmek istemiyorum, çünkü bunu kullanabilecek tüm sınıfların özel bir şey uygulamak istemiyorum. Sadece kongre yoluyla bir setError:yöntem ya da mülk sahibi olmalarını istiyorum .

Bu yapılabilir mi? Nasıl?

Şerefe,
EP



Kullanımdan kaldırılmış bir seçici uyarıya neden olur. Seçiciye erişmek artık güvenli değildir, çünkü seçici bir anda çıkarılabilir.
DawnSong

Yanıtlar:


254

Başka bir seçenek de uyarıyı şu şekilde devre dışı bırakmak olabilir:

#pragma GCC diagnostic ignored "-Wundeclared-selector"

Bu satırı, uyarının gerçekleştiği .m dosyasına yerleştirebilirsiniz.

Güncelleme:

LLVM ile de böyle çalışır:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"

... your code here ...

#pragma clang diagnostic pop

#pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" // Do your thing #pragma clang diagnostic pop
baş döndürücü

evet, @dizy durumlarında olduğu gibi. (Geç cevap için özür dilerim, ancak bildirimi kaçırdım).
Klaas

Ben alson gerekli#pragma clang diagnostic ignored "-Wselector"
max

1
@mdorseif Çoğu zaman "hariç tutmak" zorunda olduğunuz uyarısı derleme günlüğünde listelenir. Bu konsept ile herhangi bir uyarıyı sessize alabilirsiniz. Seçmenlerle ilgili görüşlerinizi eklemenize sevindim
Klaas

@epologee "

194

NSSelectorFromString'e bir göz atın .

 SEL selector = NSSelectorFromString(@"setError:");
 if ([self respondsToSelector:selector])

@selectorAnahtar kelime aracılığıyla derleme zamanında değil, çalışma zamanında bir seçici oluşturmanıza izin verir ve derleyicinin şikayet etme şansı olmaz.


Merhaba @sergio, hem sizin hem de @ jacobrelkin'in cevapları işe yarıyor. Hemen hemen aynı anda gönderildi. Varsa 'daha iyi' yanıtı seçmeme yardım eder misin?
epologee

2
Bu cevabı daha çok seviyorum çünkü daha çok "Kakao" görünüyor -y (?). sel_registerName()Zımbırtı bakışlar gizleyebilir ve doğrudan arayarak edilmemelidir tür size tür obj_msg_send () gibi, ne yaptığını bilmeden;)
Nicolas Miari

15
Xcode 5 olup olmadığından emin değilim, ancak bu uygulama ile farklı bir uyarı alıyorum: "PerformSelector, seçici bilinmediği için bir sızıntıya neden olabilir" .
Hampden123

1
@ Hampden123: bu farklı bir konu. buraya bir göz atın: stackoverflow.com/questions/7017281/…
sergio

52

Bunun nedeni, garip bir nedenden dolayı seçicinin çalışma zamanına kayıtlı olmamasıdır.

Seçiciyi şu yolla kaydetmeyi deneyin sel_registerName():

SEL setErrorSelector = sel_registerName("setError:");

if([self respondsToSelector:setErrorSelector]) {
   [self performSelector:setErrorSelector withObject:[NSError errorWithDomain:@"SomeDomain" code:1 userInfo:nil]];
}

Merhaba @jacobrelkin, hem sizin hem de @ sergio'nun cevapları işe yarıyor. Hemen hemen aynı anda gönderildi. Varsa 'daha iyi' yanıtı seçmeme yardım eder misin?
epologee

2
@epologee yine de kaputun altında NSSelectorFromStringçağırıyor sel_registerName(). Size en uygun olanı seçin.
Jacob Relkin

1
@epologee sel_registerName()Doğrudan aramanın neden yaptığınız konusunda daha açık olduğunu düşünüyorum. NSSelectorFromStringdeğil söylemek o seçici kayıt girişimi olacak size.
Jacob Relkin

8
Xcode 5 olup olmadığından emin değilim, ancak bu uygulama ile farklı bir uyarı alıyorum: "PerformSelector, seçici bilinmediği için bir sızıntıya neden olabilir" .
Hampden123

@ Max_Power89 Hayır. Aşağıdaki diğer yorumlarıma bakın. Bunun için çok fazla zaman harcamak istemedim, bu yüzden sadece başlık dosyalarını dahil ettim.
Hampden123

7

Bu mesajı # include'ing yöntemiyle uzaklaştırarak mesajımı aldım. Bu dosyadan başka bir şey kullanılmadı.


Bu daha az zarif bir çözüm olsa da, seçiciyi alan "bilinen şüphelilere" sahip olduğum için benim için çalışıyor. Ayrıca, çalışma zamanı seçici yaklaşımını uygularsam, performSelector deyiminde hala farklı bir uyarı alırım; yani "PerformSelector, seçici bilinmediği için bir sızıntıya neden olabilir" . Çok teşekkürler!
Hampden123

2
En çok oy alan cevapların ikisi de doğru değil. "Bildirilmemiş seçici" uyarısının amacı, güvenmekte olduğunuz seçicinin adını değiştirirseniz derleme zamanında hataları yakalamaktır. Bu nedenle, # güvendiğiniz yöntemi bildiren dosyayı içe aktarmak en doğrudur.
Brane

7

Bu iş parçacığına biraz geç kaldığımı fark ettim, ancak tamlık için, hedef oluşturma ayarlarını kullanarak küresel olarak bu uyarıyı kapatabilirsiniz.

'Apple LLVM uyarıları - Objective-C' bölümünde şunları değiştirin:

Undeclared Selector - NO

6

Sınıfınız setError: yöntemini uygularsa (nihai hata özelliğinin ayarlayıcısını dinamik olarak bildirerek bile) bunu arabirim dosyanızda (.h) bildirmek isteyebilirsiniz veya bu şekilde göstermek istemezseniz PrivateMethods zor hile ile deneyin:

@interface Yourclass (PrivateMethods)

- (void) yourMethod1;
- (void) yourMethod2;

@end

@ uygulamanızdan hemen önce, bu uyarıları gizlemelidir;).


Teşekkürler, ancak yöntemi bir kategoriden çağırıyorum, bu yüzden bu geçerli değil. Şerefe, EP.
epologee

Ve bazılarımız daha egzotik şeyler yapıyoruz - seçici benim durumumda bir F # nesnesine uygulandı.
James Moore

1
Bu XCode 7.1.1 / iOS PerformSelector may cause a leak because its selector is unknown
9.1'deki uyarıdan kurtulmuyor

3

Gerçekten rahat makro Gözlerinde farklı koymak .pchveya Common.histediğiniz yere veya:

#define SUPPRESS_UNDECLARED_SELECTOR_LEAK_WARNING(code)                        \
_Pragma("clang diagnostic push")                                        \
_Pragma("clang diagnostic ignored \"-Wundeclared-selector"\"")     \
code;                                                                   \
_Pragma("clang diagnostic pop")                                         \

Bu bir düzenleme var bu soruya benzer sorun için ...


3

Ekran görüntüsünde olduğu gibi Xcode'da kapatabilirsiniz:

resim açıklamasını buraya girin


Güzel bir. Yine de, uyarıyı sadece açık durumlar için devre dışı bırakmayı tercih ediyorum, "bu durumda clang yanlış, ne yaptığımı biliyorum" diyerek. Girdiniz için teşekkürler!
epologee

2

Ayrıca, uyarıyı önlemek için söz konusu nesneyi önce bir kimliğe de aktarabilirsiniz:

if ([object respondsToSelector:@selector(myMethod)]) {
    [(id)object myMethod];
}

1
Bu, bugüne kadar XC7.1'e kadar if ifadesi içeriğiyle aynı uyarıyı ortadan kaldırmaz.
Martin-Gilles Lavoie

2

Bu uyarıyı önlemenin başka bir yolu, seçici yönteminizin şöyle görünmesini sağlamaktır:

-(void) myMethod :(id) sender{
}

Herhangi bir göndereni kabul etmek veya isterseniz bir gönderen nesnesi türü belirtmek istiyorsanız "(id) göndereni" unutmayın.


0

Doğru cevap muhtemelen Xcode'u ithalat yoluyla bilgilendirmek veya seçiciyi böyle bir seçicinin varlığına kaydettirmek olsa da, benim durumumda noktalı virgül eksikti. Hatayı "düzeltmeden" önce, hatanın doğru olduğundan ve kodunuzun doğru olmadığından emin olun. Örneğin Apple'ın MVCNetworking örneğinde hatayı buldum.


Hayır, doğru cevap Xcode'u ithalat yoluyla bilgilendirmede değildi, çünkü bu ithalatlar mevcuttu. Doğru cevap yukarıdaki yanıt olarak işaretlenmişti ... doğru cevap, ancak @ sergio'nun yanıtı da sorunu çözecekti. Yanlış seçiciyi kullanmak bu sorunun konusu değildir, bu nedenle seçiciyi değiştirmek bir cevap değildir. Yine de seni aşağı oy edeceğim.
epologee

1
Bana muhtemelen bir yorum kullanmam gerektiğini hatırlattığın için teşekkürler. Söyleyebileceğim tek şey, eksik ithalatların da bu özel örnek olmasa da bu Xcode uyarısına neden olmasıdır. Çalışma zamanında bir seçici oluştururken veya yöntem çağrılarına dinamik bir şekilde yanıt verirken (örn. MethodSignatureForSelector) yalnızca NSSelectorFromString veya bu tür diğer "kayıt" seçeneklerini öneriyorum. Bunu kaydetmek, "hatanın etrafında çalıştığınız" anlamına gelir ve bu nedenle bazı durumlar için doğru değildir, çünkü uyarıyı düzeltmek için daha doğru bir yaklaşım olacaktır (clang analizi doğruysa, yani.)
Louis St-Amour

Aslında, şimdi orijinal sorunun açıkça "uygulanmış bir protokole ihtiyaç duymadan" dediğini ve ithalattan hiç bahsetmediğini görüyorum. Bu nedenle, kategorinin kendisini içe aktarmanın bu kullanıcı için en iyi seçenek olabileceğini öne sürdüm. Buradaki diğer her şey seçici olarak teknik olarak konuşarak iki kez tanımlanabilir. Evet? - Edit: Ah, bunu çok ileri götürdüm. Yanıtınız için teşekkürler, şimdi duracağım. :)
Louis St-Amour

-1

Ben thenothing yöntemi ekleyerek kurtulmak için uyarı almak mümkün (açıklama: Ben bunu düşünmedim ama zamanlanmış zamanlayıcıda googling ile buldum)

    [NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow]
                                     target:self
                                   selector:@selector(donothingatall:)
                                   userInfo:nil
                                    repeats:YES];


    [[NSRunLoop currentRunLoop] run];

    HTTPLogVerbose(@"%@: BonjourThread: Aborted", THIS_FILE);

    }
}

+ (void) donothingatall:(NSTimer *)timer
{

}

Uyarıyı nasıl gizleyeceğimi bilmeyi takdir etsem de, düzeltmek daha iyidir ve ne Sergio'nun ne de Relkin'in teknikleri bilinmeyen nedenlerle benim için işe yaramadı.


1
Birisi işe yarayacak bu çözümü okursa , gelecekteki benliğiniz de dahil olmak üzere oldukça karışık olacaktır. Mevcut olmayan bir seçiciyi arayarak ne yaptığınızı bildiğinizden ve bu nedenle bir uyarıya neden olduğunuzdan eminseniz, yanıltıcı yöntem saplamasını atlayın ve kodunuzun amacınızı ifade ettiğinden emin olun.
epologee

1
İyi bir nokta. Devralınan kodla çalışıyordum ve sadece uyarının nasıl ortadan kaldırılacağını anlamaya çalışıyordum, neden var olmayan bir seçiciye sahip olmanın temel sorusunu çözmeye çalışmıyordum. Her seferinde bir adım diyorum.
user938797
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.