Objective-C neden özel yöntemleri desteklemiyor?


123

Objective-C'de yarı-özel yöntemleri bildirmek için bir dizi strateji gördüm , ancak gerçekten özel bir yöntem yapmanın bir yolu yok gibi görünüyor. Kabul ediyorum. Ama bu niye böyle? Esasen söylüyorum her açıklamada, "bunu yapamazsınız, ama işte yakın bir tahmin."

Bir anahtar kelime sayısı uygulanan vardır ivarsmesela kapsamlarını, kontrol (üyelerin) @private, @public, @protected. Bu neden yöntemler için de yapılamıyor? Çalışma zamanının destekleyebileceği bir şey gibi görünüyor. Kaçırdığım temel bir felsefe var mı? Bu kasıtlı mı?


15
Güzel soru, btw.
bbum

5
Düzenlemelerinize göre: evet, çalışma zamanı yaptırımı çok az fayda için çok pahalı olacaktır. Derleme zamanı yaptırımı, dile iyi bir katkı olacaktır ve oldukça ulaşılabilirdir. Evet, çalışma zamanında atlatılabilir, ancak sorun değil. Programcı düşman değildir. Kapsamın amacı, programcıyı hatalardan korumaya yardımcı olmaktır.
Rob Napier

1
"Çalışma zamanını atlayamazsınız" - çalışma zamanı, mesajın gönderildiği şeydir.
Chuck

"Özel bir yöntemin bu kontrolü kısa devre yapmasının hiçbir yolu yoktur " "Atlatmak" mı demek istediniz? ;-)
Constantino Tsarouhas

Yanıtlar:


103

Cevap ... şey ... basit. Aslında basitlik ve tutarlılık.

Objective-C, yöntem gönderimi sırasında tamamen dinamiktir. Özellikle, her yöntem gönderimi, diğer her yöntem gönderimi ile tamamen aynı dinamik yöntem çözüm noktasından geçer. Çalışma zamanında, her yöntem uygulaması tam olarak aynı görünürlüğe sahiptir ve yöntemlerle ve seçicilerle çalışan Objective-C çalışma zamanı tarafından sağlanan tüm API'ler tüm yöntemlerde eşit şekilde aynı şekilde çalışır.

Birçoğunun yanıtladığı gibi (hem burada hem de diğer sorularda), derleme zamanı özel yöntemler desteklenir; bir sınıf, genel kullanıma açık arabiriminde bir yöntem bildirmezse, o zaman kodunuz söz konusu olduğunda bu yöntem de mevcut olmayabilir. Başka bir deyişle, projenizi uygun şekilde düzenleyerek derleme sırasında istenen tüm çeşitli görünürlük kombinasyonlarını elde edebilirsiniz.

Aynı işlevselliği çalışma zamanına kopyalamak çok az fayda sağlar. Muazzam miktarda karmaşıklık ve ek yük getirir. Ve tüm bu karmaşıklığa rağmen, en sıradan geliştiricinin, sözde "özel" yöntemlerinizi yürütmesini engellemez.

DÜZENLEME: Fark ettiğim varsayımlardan biri, özel mesajların çalışma zamanından geçerek potansiyel olarak büyük bir ek yüke neden olması gerektiğidir. Bu kesinlikle doğru mu?

Evet öyle. Bir sınıfın uygulayıcısının uygulamadaki tüm Objective-C özelliğini kullanmak istemeyeceğini varsaymak için hiçbir neden yoktur ve bu dinamik gönderimin gerçekleşmesi gerektiği anlamına gelir. Ancak , özel yöntemlerin özel bir varyantı tarafından gönderilememesinin belirli bir nedeni yoktur objc_msgSend(), çünkü derleyici özel olduklarını bilirdi; yani bu, Classyapıya yalnızca özel bir yöntem tablosu eklenerek sağlanabilir .

Özel bir yöntemin bu kontrolü kısa devre yapmasının veya çalışma süresini atlamasının bir yolu yok mu?

Bu çalışma zamanını atlamak olamazdı, ama çalışma zamanı olmaz mutlaka özel yöntemler için herhangi kontrol yapmak zorundayız.

Bununla birlikte, bir üçüncü tarafın objc_msgSendPrivate()bir nesneyi kasıtlı olarak o nesnenin uygulanmasının dışında arayamaması için hiçbir neden yoktur ve bazı şeyler (örneğin KVO) bunu yapmak zorunda kalır. Gerçekte, bu sadece bir kongre olur ve pratikte özel yöntemlerin seçicilerinin önekini koymaktan veya onlardan arayüz başlığında bahsetmemekten biraz daha iyidir.

Ancak bunu yapmak, dilin saf dinamik doğasının altını oyacaktır. Artık her yöntem gönderimi aynı bir gönderme mekanizmasından geçmeyecektir. Bunun yerine, çoğu yöntemin bir şekilde davrandığı ve küçük bir avucunun farklı olduğu bir durumda kalırsınız.

Cocoa'da Objective-C'nin tutarlı dinamizmi üzerine inşa edilmiş birçok mekanizma olduğundan, bu çalışma zamanının ötesine uzanır. Örneğin, hem Anahtar Değer Kodlaması hem de Anahtar Değer Gözleminin özel yöntemleri desteklemek için çok büyük ölçüde değiştirilmesi gerekir - büyük olasılıkla sömürülebilir bir boşluk yaratarak - ya da özel yöntemler uyumsuz olur.


49
+1 Objective-C (bazı yönlerden), programcıların her seferinde derleyici / çalışma zamanı tarafından eline tokatlanmak yerine belirli bir miktar disiplin sergilemelerinin beklendiği "büyük çocuk" bir dildir. Onu ferahlatıcı buluyorum. Benim için, derleme / bağlama sırasında yöntem görünürlüğünü kısıtlamak yeterli ve tercih edilir.
Quinn Taylor

11
Daha fazla python "obj-c-ic" :). Guido, PyObjC'nin 1. sürümünü oluşturmak da dahil olmak üzere Python'u NeXT sistemlerinde sürdürmede oldukça proaktifti. Böylece, ObjC python'u bir şekilde etkiledi .
bbum

3
Hayati yardımsever diktatörün ilginç tarihi hikayesi ve efsanevi NeXT sistemiyle geçişleri için +1.
pokstad

5
Teşekkür ederim. Python, Java ve Objective-C'nin tümü, [SmallTalk'a] oldukça benzeyen çalışma zamanı nesne modellerine sahiptir. Java, doğrudan Objective-C'den türetildi. Python, birden fazla ilham verici paralel bir kurs yürüttü, ancak Guido kesinlikle NeXTSTEP'i yakından inceledi.
bbum

1
Bunun dışında lisansına güvenmem ve kesinlikle clang'ı gcc'ye tercih ederim. Ama kesinlikle iyi bir ilk adım.
Cthutu

18

Çalışma zamanı bunu destekleyebilir, ancak maliyeti çok büyük olacaktır. Gönderilen her seçicinin o sınıf için özel mi yoksa genel mi olduğunun kontrol edilmesi gerekir veya her sınıfın iki ayrı dağıtım tablosunu yönetmesi gerekir. Bu, örnek değişkenleri için aynı değildir çünkü bu koruma seviyesi derleme zamanında yapılır.

Ayrıca, çalışma zamanının, özel bir mesaj gönderenin alıcı ile aynı sınıfta olduğunu doğrulaması gerekir. Özel yöntemleri de atlayabilirsiniz; sınıf kullanılmışsa instanceMethodForSelector:, IMPözel yöntemi doğrudan çağırmaları için döndürülenleri başka herhangi bir sınıfa verebilir .

Özel yöntemler mesaj gönderimini atlayamaz. Aşağıdaki senaryoyu düşünün:

  1. Bir sınıfın AllPublicgenel bir örnek yöntemi vardırdoSomething

  2. Başka bir sınıfın HasPrivateda adı verilen özel bir örnek yöntemi vardırdoSomething

  3. Her ikisinin de herhangi bir sayıda örneğini içeren bir dizi oluşturursunuz AllPublicveHasPrivate

  4. Aşağıdaki döngüye sahipsiniz:

    for (id anObject in myArray)
        [anObject doSomething];

    Bu döngüyü içeriden AllPublicçalıştırırsanız, çalışma zamanının sizi örnekler doSomethingüzerinde göndermeyi durdurması gerekirdi HasPrivate, ancak bu döngü HasPrivatesınıfın içinde olsaydı kullanılabilir olurdu .


1
Bunun bir bedeli olacağına katılıyorum. Belki de elde taşınan bir cihazda istediğiniz bir şey değildir. Aksi takdirde muazzam niteleyiciyi destekleyebilir misiniz? Bir masaüstü sistemde maliyet gerçekten önemli midir?
Rob Jones

1
Bunu yapmadım ama haklı olabilirsin. Objective-C, C ++ 'nın derleme zamanı yöntemi çağrısına karşı çalışma zamanı mesaj gönderimi içerir, bu nedenle bir çalışma zamanı kontrolüne karşı derleme zamanı kontrolünden bahsediyor olursunuz.
Remus Rusanu

Özel yöntemleri desteklememenin ana sebebinin performanstan kaynaklanması gerçekten garip görünüyor. Bence Apple, performans artışı olsa da olmasa da özel yöntemlerin çok gerekli olduğunu düşünmedi. Aksi takdirde milyar dolarlık şirketleri için farklı bir dil seçmeleri gerekirdi.
pokstad

1
Özel yöntemler eklemek, yalnızca çalışma zamanının uygulanmasını karmaşıklaştırmakla kalmaz, dilin anlamını da karmaşıklaştırır. Erişim kontrolü, statik dillerde basit bir kavramdır, ancak çok fazla kavramsal ek yük getirecek ve birçok "neden bu işe yaramıyor?" sorular.
Jens Ayton

7
Özel yöntemler size gerçekten ne satın alırdı? Sonuçta Objective-C, C tabanlı bir dildir. Bu nedenle, eğer birisi sizin sürecinizde çalışan bir koda sahipse, herhangi bir API'nin ne kadar özel ya da karmaşık olabileceğine bakılmaksızın sürecinizi kolayca p0wnz edebilir.
bbum

13

Şimdiye kadar gönderilen cevaplar, soruyu felsefi bir perspektiften cevaplamak için iyi bir iş çıkarıyor, bu yüzden daha pragmatik bir neden öne süreceğim: Dilin anlambilimini değiştirerek ne kazanılabilir? Özel yöntemleri etkili bir şekilde "gizlemek" için yeterince basit. Örnek olarak, bir başlık dosyasında aşağıdaki gibi tanımlanmış bir sınıfınız olduğunu düşünün:

@interface MyObject : NSObject {}
- (void) doSomething;
@end

"Özel" yöntemlere ihtiyacınız varsa, bunu uygulama dosyasına da koyabilirsiniz:

@interface MyObject (Private)
- (void) doSomeHelperThing;
@end

@implementation MyObject

- (void) doSomething
{
    // Do some stuff
    [self doSomeHelperThing];
    // Do some other stuff;
}

- (void) doSomeHelperThing
{
    // Do some helper stuff
}

@end

Elbette, C ++ / Java özel yöntemleriyle tam olarak aynı değil , ancak yeterince yakın, öyleyse neden dilin anlamını ve ayrıca derleyiciyi, çalışma zamanını vb. Kabul edilebilir bir şekilde öykünmüş bir özellik eklemek için değiştirin. yolu? Diğer yanıtlarda da belirtildiği gibi, mesaj ileten anlambilim - ve bunların çalışma zamanı yansımasına dayanmaları - "özel" mesajların işlenmesini önemsiz hale getirecektir.


1
Bu yaklaşımla ilgili sorun, birisinin sınıfınızın alt sınıfına girdiğinde özel yöntemleri (bilmeden bile olsa) geçersiz kılabilmesidir. Sanırım, esasen geçersiz kılınması olası olmayan isimler seçmelisiniz.
dreamlax

3
Bu da bana bir hack'lemenin üstüne bir hack gibi geliyor.
Rob Jones

1
@Mike: Apple, önde gelen alt çizgilere sahip yöntem adlarının açıkça yalnızca Apple için ayrıldığını belirtti: developer.apple.com/mac/library/documentation/Cocoa/Conceptual/… . Önerilen alternatif, iki büyük harfle önek ve ardından bir alt çizgi kullanmaktır.
dreamlax

8
Ayrıca, diğer programcıların onu kimin yazdığını bilmesi için yöntemden sonra SSN'nizi de ekleyin. = D İsim alanları, onlara ihtiyacım var !!!
pokstad

2
Geçersiz
kıldığını

7

En kolay çözüm, yalnızca Objective-C sınıflarınızdaki bazı statik C işlevlerini bildirmektir. Bunlar yalnızca static anahtar sözcüğü için C kurallarına göre dosya kapsamına sahiptir ve bu nedenle yalnızca o sınıftaki yöntemler tarafından kullanılabilirler.

Hiç telaş yok.


Bunların @ uygulama bölümünün dışında tanımlanması gerekiyor mu?
Rob Jones

@Rob - hayır, sınıf uygulamanızın içinde tanımlanabilirler (ve büyük olasılıkla olmalıdır).
Cromulent

6

Evet, derleyici (ler) tarafından C ++: ad değiştirme işleminin işlenmesi için zaten kullanılan bir teknik kullanılarak çalışma zamanını etkilemeden yapılabilir.

Bu yapılmadı çünkü kodlama problemi alanındaki diğer tekniklerin (örneğin, ön ek veya alt çizgi) yeterince aşabildiği bazı önemli zorlukları çözeceği belirlenmedi. IOW, kökleşmiş alışkanlıkların üstesinden gelmek için daha fazla acıya ihtiyacınız var.

Sözdizimine özel yöntemler ekleyen ve derleme sırasında tek başına tanıdığı (ve hemen unuttuğu) karıştırılmış adlar üreten clang veya gcc'ye yamalara katkıda bulunabilirsiniz. Ardından Objective-C topluluğundaki diğerleri bunun gerçekten değerli olup olmadığını belirleyebileceklerdi. Bu şekilde, geliştiricileri ikna etmeye çalışmaktan daha hızlı olması muhtemeldir.


2
Derleme zamanı adının karıştırılması, XIB dosyalarında görünenler ve NSSelectorFromString () ve KeyValueCoding & friends gibi şeylere aktarılabilenler de dahil olmak üzere tüm yöntem seçicileri karıştırmanız gerektiğinden, varsayılandan çok daha zordur ...
bbum

1
Evet, araç zinciri boyunca özel yöntemler için destek sağlamak isteseydiniz daha fazla işin içine girecektir. Derleyicinin sembol tablosunun saklanması ve bazı araç zinciri api aracılığıyla erişilebilir olması gerekir. Apple'ın geliştiricilere, zaman ve kararlılık izin verdiği ölçüde yeterince önemli olan yetenekleri kademeli olarak sunması gerektiği ilk sefer olmayacaktı. Bununla birlikte, özel yöntemler söz konusu olduğunda: çabayı üstlenmek için yeterli bir kazanç olup olmadığı sorgulanabilir. Bu diğer mekanizmalarla sınıfın dışında erişilebilir olmaları daha da şüphelidir.
Huperniketes

1
Yalnızca derleme zamanı zorunluluğu + ad değiştirme, birinin sınıfın yöntem listesinde yürümesini ve onu orada bulmasını nasıl engeller?
dreamlax

Olmaz. Cevabım yalnızca OP'nin sorduğu soruyu ele alıyor.
Huperniketes

Clang'a özel yöntemler eklemeye çalışmayı düşündüm, özel yöntemlerin iyi olacağını düşünmemin bir nedeni, bunların doğrudan basit c işlevleri gibi çağrılabilmeleriydi ve sonra tüm olağan C işlevi optimizasyonlarına sahip olabilirsiniz. Zaman yüzünden hiç rahatsız olmadım ve bunu sadece c kullanarak yapabilirsiniz.
Nathan Günü

4

Esasen, Objective-C'nin yöntem çağrılarının mesaj iletme biçimi ile ilgisi vardır. Herhangi bir mesaj herhangi bir nesneye gönderilebilir ve nesne mesaja nasıl yanıt vereceğini seçer. Normalde, mesajdan sonra adlandırılan yöntemi çalıştırarak yanıt verir, ancak başka yollarla da yanıt verebilir. Bu, özel yöntemleri tamamen imkansız hale getirmez - Ruby bunu benzer bir mesaj iletme sistemiyle yapar - ancak onları biraz garip hale getirir.

Ruby'nin özel metotları uygulaması bile gariplik nedeniyle insanlar için biraz kafa karıştırıcıdır (nesneye bu listedekiler dışında istediğiniz herhangi bir mesajı gönderebilirsiniz !). Esasen Ruby, özel yöntemlerin açık bir alıcıyla çağrılmasını yasaklayarak çalışmasını sağlar. Objective-C'de, Objective-C'nin bu seçeneği olmadığı için daha fazla çalışma gerekir.


1

Bu, Objective-C'nin çalışma zamanı ortamıyla ilgili bir sorundur. C / C ++ , okunamayan makine koduna derlenirken, Objective-C hala dizeler olarak yöntem adları gibi bazı insan tarafından okunabilir nitelikleri korur . Bu, Objective-C'ye yansıtıcı özellikleri gerçekleştirme yeteneği verir .

DÜZENLEME: Sıkı özel yöntemler olmadan yansıtıcı bir dil olmak, Objective-C'yi daha "pitonik" kılar, çünkü hangi yöntemleri çağırabileceklerini kısıtlamak yerine kodunuzu kullanan diğer insanlara güvenirsiniz. Çift alt çizgi gibi adlandırma kurallarını kullanmak, kodunuzu sıradan bir istemci kodlayıcıdan gizlemek anlamına gelir, ancak kodlayıcıların daha ciddi işler yapmasına gerek kalmaz.


Kitaplığınızın tüketicileri özel yöntemlerinizi yansıtabilseler, onları da arayamazlar mı?
Jared Updike

Nereye bakacaklarını biliyorlarsa, insanlar iPhone'daki belgelenmemiş kitaplıkları böyle kullanmıyor mu? İPhone ile ilgili sorun, uygulamanızı herhangi bir özel API kullanmak için kabul etmeme riskinizdir.
pokstad

Özel yöntemlere yansıtma yoluyla erişirlerse, hak ettiklerini elde ederler. Herhangi bir hata sizin hatanız değildir.
gnasher729

1

Sorunun yorumuna bağlı olarak iki cevap vardır.

Birincisi, yöntem uygulamasını arayüzden gizlemektir. Bu, tipik olarak isimsiz bir kategoriyle kullanılır (örn. @interface Foo()). Bu, nesnenin bu mesajları göndermesine izin verir, ancak diğerlerini göndermez - yine de biri yanlışlıkla (veya başka şekilde) geçersiz kılabilir.

Bunun performans ve satır içi olduğu varsayımına dayanan ikinci cevap, bunun yerine yerel bir C işlevi olarak mümkün kılınır. Bir 'private foo ( NSString *arg)' yöntemi istiyorsanız, bunu yaparsınız void MyClass_foo(MyClass *self, NSString *arg)ve C işlevi gibi çağırırsınız MyClass_foo(self,arg). Sözdizimi farklıdır, ancak C ++ 'ın özel yöntemlerinin mantıklı performans özellikleriyle hareket eder.

Bu soruyu yanıtlasa da, isimsiz kategorinin bunu yapmanın çok daha yaygın olan Objective-C yolu olduğunu belirtmeliyim.


0

Objective-C özel yöntemleri desteklemez çünkü onlara ihtiyaç duymaz.

C ++ 'da, her yöntem sınıfın bildiriminde görünür olmalıdır. Başlık dosyası dahil olmak üzere birinin göremediği yöntemlere sahip olamazsınız. Dolayısıyla, uygulamanızın dışındaki kodun kullanmaması gereken yöntemleri istiyorsanız, seçeneğiniz yoktur, derleyici size bazı araçlar vermelidir, böylece yöntemin kullanılmaması gerektiğini söyleyebilirsiniz, bu "özel" anahtar kelimedir.

Objective-C'de, başlık dosyasında olmayan yöntemlere sahip olabilirsiniz. Dolayısıyla, yöntemi başlık dosyasına eklemeyerek aynı amaca çok kolay ulaşırsınız. Özel yöntemlere gerek yok. Objective-C, özel yöntemleri değiştirdiğiniz için bir sınıfın her kullanıcısını yeniden derlemenize gerek kalmaması avantajına da sahiptir.

Örneğin başlık dosyasında (artık değil) bildirmeniz gereken değişkenler, @private, @public ve @protected mevcuttur.


0

Buradaki eksik cevap şudur: çünkü özel yöntemler, geliştirilebilirlik açısından kötü bir fikirdir. Bir yöntemi yazarken özel yapmak iyi bir fikir gibi görünebilir, ancak bu bir erken bağlama biçimidir. Bağlam değişebilir ve daha sonraki bir kullanıcı farklı bir uygulama kullanmak isteyebilir. Biraz kışkırtıcı: "Çevik geliştiriciler özel yöntemler kullanmaz"

Bir bakıma Smalltalk gibi, Objective-C de yetişkin programcılar içindir. Orijinal geliştiricinin arayüzün ne olması gerektiğini varsaydığını bilmeye değer veriyoruz ve uygulamayı değiştirmemiz gerekirse sonuçlarla başa çıkma sorumluluğunu üstleniyoruz. Yani evet, felsefe, uygulama değil.


Buna ek oy verdim çünkü olumsuz oyu hak etmiyor. Stephan'ın dediği gibi, "özel" yöntemlerin gerekli olmadığına dair bir argüman var ve dinamik ve statik yazım hakkındaki argümanlara benziyor, çünkü tercih ettiğiniz sonuç ne olursa olsun, her iki tarafın da bir noktası var.
alastair
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.