Statik kütüphanedeki Objective-C kategorileri


153

Statik kitaplığı iPhone projesine nasıl düzgün bir şekilde bağlayacağımı yönlendirebilir misiniz? Uygulama projesine eklenen statik kütüphane projesini doğrudan bağımlılık (hedef -> genel -> doğrudan bağımlılıklar) olarak kullanıyorum ve tüm işler tamam, ancak kategoriler. Statik kitaplıkta tanımlanan bir kategori uygulamada çalışmıyor.

Öyleyse sorum, bazı kategorilerdeki statik kitaplığın diğer projeye nasıl ekleneceği?

Ve genel olarak, diğer projelerin uygulama projesi kodunda kullanmak için en iyi uygulama nedir?


1
iyi, bazı cevaplar buldu ve bu soru zaten burada cevaplanmış gibi görünüyor (özür dilerim özledim stackoverflow.com/questions/932856/… )
Vladimir

Yanıtlar:


228

Çözüm: Xcode 4.2'den itibaren, yalnızca kitaplığa (kitaplığın kendisine değil) bağlanan uygulamaya gitmeniz ve Proje Gezgini'nde projeyi tıklamanız, uygulamanızın hedefini tıklamanız, ardından ayarları oluşturmanız ve ardından "Diğer Bağlayıcı Bayrakları "seçeneğini tıklayın, + düğmesini tıklayın ve '-ObjC' ekleyin. '-all_load' ve '-force_load' artık gerekli değil.

Ayrıntılar: Çeşitli forumlarda, bloglarda ve elma dokümanlarında bazı cevaplar buldum. Şimdi araştırmalarımın ve denemelerimin kısa bir özetini yapmaya çalışıyorum.

Sorun (Apple Teknik Soru-Cevap QA1490 https://developer.apple.com/library/content/qa/qa1490/_index.html kaynağından alıntı) nedeniyle oluştu :

Objective-C her işlev (veya Objective-C'de yöntem) için bağlayıcı sembolleri tanımlamaz - bunun yerine bağlayıcı sembolleri yalnızca her sınıf için oluşturulur. Önceden var olan bir sınıfı kategorilerle genişletirseniz, bağlayıcı temel sınıf uygulamasının ve kategori uygulamasının nesne kodunu ilişkilendireceğini bilmez. Bu, sonuçta ortaya çıkan uygulamada oluşturulan nesnelerin kategoride tanımlanan bir seçiciye yanıt vermesini önler.

Ve onların çözümü:

Bu sorunu gidermek için <a0> </a0>, statik kitaplığı bağlayıcı -ObjC seçeneği geçirmelidir. Bu bayrak, bağlayıcının kütüphanedeki Objective-C sınıfını veya kategorisini tanımlayan her nesne dosyasını yüklemesine neden olur. Bu seçenek genellikle daha büyük bir yürütülebilir dosya ile sonuçlanır (uygulamaya yüklenen ek nesne kodu nedeniyle), varolan sınıflarda kategoriler içeren etkili Objective-C statik kitaplıklarının başarıyla oluşturulmasına izin verir.

ayrıca iPhone Geliştirme SSS bölümünde de tavsiye var:

Statik bir kitaplıktaki tüm Objective-C sınıflarını nasıl bağlarım? Diğer Bağlayıcı Bayrakları oluşturma ayarını -ObjC olarak ayarlayın.

ve bayrak açıklamaları:

- all_load Statik arşiv kitaplıklarının tüm üyelerini yükler.

- ObjC Bir Objective-C sınıfı veya kategorisi uygulayan tüm statik arşiv kütüphanelerinin üyelerini yükler.

- force_load (path_to_archive) Belirtilen statik arşiv kitaplığının tüm üyelerini yükler. Not: -all_load, tüm arşivlerin tüm üyelerini yüklenmeye zorlar. Bu seçenek belirli bir arşivi hedeflemenizi sağlar.

* Uygulamanın ikili boyutunu azaltmak ve all_load'un bazı durumlarda neden olabileceği çakışmaları önlemek için force_load komutunu kullanabiliriz.

Evet, projeye eklenen * .a dosyalarıyla çalışır. Yine de doğrudan bağımlılık olarak eklenen lib projesinde sorunlar yaşadım. Ama daha sonra bunun benim hatam olduğunu gördüm - doğrudan bağımlılık projesi muhtemelen düzgün eklenmedi. Ben kaldırmak ve adımlarla tekrar eklemek zaman:

  1. Uygulama projesinde lib proje dosyasını sürükleyip bırakın (veya Project-> Projeye ekle… ile ekleyin).
  2. Lib proje simgesinde - mylib.a dosya adı gösterilen oku tıklayın, bu mylib.a dosyasını sürükleyin ve Hedef -> İkili Kütüphaneye Bağla grubuna bırakın.
  3. Hedef bilgilerini yumruk sayfasında aç (Genel) ve lib'imi bağımlılıklar listesine ekle

bundan sonra her şey yolunda. Benim durumumda "-ObjC" bayrağı yeterliydi.

Ayrıca http://iphonedevelopmentexperiences.blogspot.com/2010/03/categories-in-static-library.html blogundan bir fikir ilgimi çekti . Yazar -all_load veya -ObjC bayrağını ayarlamadan lib kategorisini kullanabileceğini söylüyor. Sadece kategori h / m dosyaları eklemek boş kukla sınıf arayüzü / bağlayıcı bu dosyayı kullanmaya zorlamak için. Ve evet, bu hile işi yapıyor.

Ancak yazar, kukla nesneyi bile başlattığını söyledi. Mm… Bulduğum gibi kategori dosyasından açıkça bazı "gerçek" kodları çağırmalıyız. Bu yüzden en azından sınıf fonksiyonu çağrılmalıdır. Ve hatta kukla bir sınıfa ihtiyacımız yok. Tekli c işlevi de aynısını yapar.

Yani lib dosyalarını şöyle yazarsak:

// mylib.h
void useMyLib();

@interface NSObject (Logger)
-(void)logSelf;
@end


// mylib.m
void useMyLib(){
    NSLog(@"do nothing, just for make mylib linked");
}


@implementation NSObject (Logger)
-(void)logSelf{
    NSLog(@"self is:%@", [self description]);
}
@end

ve useMyLib () çağrısı yaparsak; herhangi bir yerde App projesinde herhangi bir sınıfta logSelf kategori yöntemini kullanabiliriz;

[self logSelf];

Ve konuyla ilgili daha fazla blog:

http://t-machine.org/index.php/2009/10/13/how-to-make-an-iphone-static-library-part-1/

http://blog.costan.us/2009/12/fat-iphone-static-libraries-device-and.html


8
Apple teknik notunun, "Bu sorunu gidermek için statik kitaplıkla hedeflenen bağlantının -ObjC seçeneğini bağlayıcıya geçirmesi" söylenecek şekilde değiştirildiği görülüyor. bu da yukarıda belirtilenlerin tersidir. Sadece uygulamayı bağlarken kütüphanenin kendisini eklemeniz gerektiğini doğruladık.
Ken Aspeslagh

Developer.apple.com/library/mac/#qa/qa1490/_index.html dokümanına göre , -all_load veya -force_load bayrağı kullanmalıyız. Belirtildiği gibi, linker 64bit Mac App ve iPhone App'te hata var. "Önemli: 64 bit ve iPhone OS uygulamaları için, -ObjC'nin yalnızca kategori içeren ve sınıf içermeyen statik kitaplıklardan nesne dosyaları yüklemesini engelleyen bir bağlayıcı hatası vardır. Geçici çözüm -all_load veya -force_load bayraklarını kullanmaktır."
Robin

2
@Ken Aspelagh: Teşekkürler, aynı sorunu yaşadım. -ObjC ve -all_load bayraklarının kütüphaneye değil uygulamanın kendisine eklenmesi gerekir .
titaniumdecoy

3
Harika bir cevap, ancak bu soruya yeni gelenler sorunun artık güncel olmadığını belirtmelidir. Tonklon'un cevabına bir göz atın stackoverflow.com/a/9224606/322748 (all_load / force_load artık gerekli değil)
Jay Peyer

Neredeyse yarım saat boyunca bu şeylere takılıp kaldım ve bir deneme yanılma ile bunu başardım. Herhangi bir şekilde teşekkürler. Bu cevap +1 değerinde ve anladınız !!!
Deepukjayan

118

Vladimir'in cevabı aslında oldukça iyi, ancak burada biraz daha arka plan bilgisi vermek istiyorum. Belki bir gün birileri cevabımı bulur ve yardımcı olabilir.

Derleyici kaynak dosyaları (.c, .cc, .cpp, .m) nesne dosyalarına (.o) dönüştürür. Kaynak dosya başına bir nesne dosyası vardır. Nesne dosyaları semboller, kodlar ve veriler içerir. Nesne dosyaları işletim sistemi tarafından doğrudan kullanılamaz.

Şimdi dinamik bir kütüphane (.dylib), bir çerçeve, yüklenebilir bir paket (.bundle) veya yürütülebilir bir ikili dosya oluştururken, bu nesne dosyaları, işletim sisteminin "kullanılabilir" olarak düşündüğü bir şey üretmek için bağlayıcı tarafından birbirine bağlanır, örn. doğrudan belirli bir bellek adresine yükleyin.

Ancak, statik bir kitaplık oluştururken, tüm bu nesne dosyaları büyük bir arşiv dosyasına eklenir, dolayısıyla statik kitaplıkların uzantısı (arşiv için .a). Bu nedenle .a dosyası, nesne (.o) dosyalarının arşivinden başka bir şey değildir. Bir TAR arşivini veya sıkıştırılmadan bir ZIP arşivini düşünün. Tek bir .a dosyasını tüm .o dosyaları grubundan kopyalamak daha kolaydır (.class dosyalarını kolay dağıtım için bir .jar arşivine paketlediğiniz Java'ya benzer).

Bir ikili dosyayı statik kitaplığa (= arşiv) bağlarken, bağlayıcı arşivdeki tüm sembollerin bir tablosunu alır ve bu sembollerden hangilerinin ikili dosyalar tarafından referanslandığını kontrol eder. Yalnızca başvurulan sembolleri içeren nesne dosyaları gerçekten bağlayıcı tarafından yüklenir ve bağlama işlemi tarafından dikkate alınır. Örneğin, arşivinizde 50 nesne dosyası varsa, ancak yalnızca 20'si ikili dosya tarafından kullanılan simgeler içeriyorsa, yalnızca 20 tanesi bağlayıcı tarafından yüklenirse, diğer 30'u bağlama sürecinde tamamen yok sayılır.

Bu diller, C ve C ++ kodu için oldukça iyi çalışır, çünkü bu diller derleme zamanında mümkün olduğunca yapmaya çalışır (C ++ ayrıca yalnızca çalışma zamanı özelliklerine de sahiptir). Ancak Obj-C farklı bir dildir. Obj-C büyük ölçüde çalışma zamanı özelliklerine bağlıdır ve birçok Obj-C özelliği aslında yalnızca çalışma zamanı özellikleridir. Obj-C sınıfları aslında C fonksiyonları veya global C değişkenleri ile karşılaştırılabilir sembollere sahiptir (en azından mevcut Obj-C çalışma zamanında). Bağlayıcı, bir sınıfa başvurulup başvurulmadığını görebilir, böylece kullanımda olan bir sınıfı belirleyebilir. Statik kitaplıktaki bir nesne dosyasından bir sınıf kullanırsanız, linker kullanımda olan bir sembolü gördüğünden, bu nesne dosyası bağlayıcı tarafından yüklenir. Kategoriler yalnızca çalışma zamanı özelliğidir, kategoriler sınıflar veya işlevler gibi simgeler değildir ve bu da bir bağlayıcının bir kategorinin kullanımda olup olmadığını belirleyemeyeceği anlamına gelir.

Bağlayıcı Obj-C kodu içeren bir nesne dosyası yüklerse, bunun tüm Obj-C parçaları her zaman bağlama aşamasının bir parçasıdır. Dolayısıyla, kategorileri içeren bir nesne dosyası yüklenir, çünkü ondan herhangi bir sembol "kullanımda" kabul edilir (bir sınıf olsun, bir fonksiyon olsun, global bir değişken olsun), kategoriler de yüklenir ve çalışma zamanında kullanılabilir olacaktır . Ancak nesne dosyasının kendisi yüklenmezse, içindeki kategoriler çalışma zamanında kullanılamaz. İçeren bir nesne dosyası sadece kategoriler edilir asla o içerdiğinden yüklenen hiçbir sembolleri bağlayıcı olacağını hiç "kullanımda" düşünün. Ve buradaki tüm sorun bu.

Birkaç çözüm önerildi ve şimdi tüm bunların birlikte nasıl oynandığını bildiğinize göre, önerilen çözüme bir göz atalım:

  1. Bir çözüm, -all_loadbağlayıcı çağrısına eklemektir . Bu bağlayıcı bayrağı gerçekte ne yapacak? Aslında, bağlayıcıya aşağıdaki "Kullanılan herhangi bir sembol görüp görmediğinize bakılmaksızın tüm arşivlerin tüm nesne dosyalarını yükle " komutunu söyler . Tabii ki bu işe yarar ; ancak oldukça büyük ikili dosyalar da üretebilir.

  2. Başka bir çözüm, -force_loadarşiv yolunu içeren bağlayıcı çağrısına eklemektir . Bu bayrak tam olarak aynı şekilde çalışır -all_load, ancak yalnızca belirtilen arşiv için geçerlidir. Tabii ki bu da işe yarayacak.

  3. En popüler çözüm -ObjClinker çağrısına eklemektir . Bu bağlayıcı bayrağı gerçekte ne yapacak? Bu bayrak, bağlayıcıya " Herhangi bir Obj-C kodu içerdiklerini görürseniz, tüm arşivlerdeki tüm nesne dosyalarını yükle " komutunu bildirir . Ve "herhangi bir Obj-C kodu" kategorileri içerir. Bu da işe yarayacak ve Obj-C kodu içermeyen nesne dosyalarının yüklenmesini zorlamayacaktır (bunlar yalnızca istek üzerine yüklenir).

  4. Başka bir çözüm, oldukça yeni Xcode derleme ayarıdır Perform Single-Object Prelink. Bu ayar ne yapacak? Etkinleştirilirse, tüm nesne dosyaları (unutmayın, kaynak dosya başına bir tane vardır) tek bir nesne dosyasına (gerçek bağlantı olmayan, dolayısıyla PreLink adı ) birleştirilir ve bu tek nesne dosyası (bazen "ana nesne olarak da adlandırılır) dosya ") daha sonra arşive eklenir. Artık ana nesne dosyasının herhangi bir sembolü kullanımda olarak kabul edilirse, tüm ana nesne dosyası kullanımda kabul edilir ve bu nedenle tüm Objective-C bölümleri her zaman yüklenir. Sınıflar normal semboller olduğundan, tüm kategorileri almak için böyle bir statik kütüphaneden tek bir sınıf kullanmak yeterlidir.

  5. Nihai çözüm, Vladimir'in cevabının sonuna eklediği hiledir. Yalnızca kategori bildiren herhangi bir kaynak dosyaya bir " sahte sembol " yerleştirin. Çalışma zamanında kategorilerden herhangi birini kullanmak istiyorsanız , derleme zamanında sahte sembole bir şekilde başvurduğunuzdan emin olun , çünkü bu, nesne dosyasının bağlayıcı tarafından yüklenmesine ve dolayısıyla içindeki tüm Obj-C koduna neden olur. Örneğin, boş bir işlev gövdesine sahip bir işlev olabilir (çağrıldığında hiçbir şey yapmaz) veya erişilen küresel bir değişken olabilir (örn.intokunduktan veya yazıldıktan sonra bu yeterlidir). Yukarıdaki tüm diğer çözümlerden farklı olarak, bu çözüm çalışma zamanında hangi kategorilerin kullanılabilir olduğunu kontrol eder derlenmiş koda kaydırır (bağlantılarını ve kullanılabilir olmalarını istiyorsa, sembole erişir, aksi takdirde sembole erişmez ve bağlayıcı göz ardı eder o).

Hepsi bu kadar millet.

Oh, bekleyin, bir şey daha var:
Bağlayıcının adlı bir seçeneği var -dead_strip. Bu seçenek ne işe yarar? Bağlayıcı bir nesne dosyası yüklemeye karar verdiyse, kullanılsın veya kullanılmasın, nesne dosyasının tüm sembolleri bağlı ikili dosyaya dahil olur. Örneğin, bir nesne dosyası 100 işlev içerir, ancak bunlardan yalnızca biri ikili dosya tarafından kullanılır, nesne işlevlerinin bir bütün olarak eklendiği veya hiç eklenmediği için, 100 işlevin tümü hala ikiliye eklenir. Kısmen bir nesne dosyası eklemek genellikle bağlayıcılar tarafından desteklenmez.

Ancak, bağlayıcıya "ölü şerit" demeniz halinde, bağlayıcı önce tüm nesne dosyalarını ikiliye ekler, tüm referansları çözer ve sonunda ikiliyi kullanılmayan semboller için tarar (veya yalnızca kullanılmayan diğer semboller tarafından kullanılır) kullanımı). Kullanılmadığı tespit edilen tüm semboller, optimizasyon aşamasının bir parçası olarak kaldırılır. Yukarıdaki örnekte, kullanılmayan 99 işlev tekrar kaldırılmıştır. Eğer gibi seçenekleri kullanabilirsiniz, bu çok yararlıdır -load_all, -force_loadya Perform Single-Object Prelinkbu seçenekler kolayca bazı durumlarda önemli ölçüde ikili boyutları havaya uçurmak çünkü ve ölü sıyırma tekrar kullanılmayan kod ve verileri kaldırılır.

Ölü sıyırma C kodu için çok iyi çalışır (örneğin, kullanılmayan fonksiyonlar, değişkenler ve sabitler beklendiği gibi kaldırılır) ve ayrıca C ++ için oldukça iyi çalışır (örneğin, kullanılmayan sınıflar kaldırılır). Mükemmel değildir, bazı durumlarda bazı semboller çıkarılsa bile kaldırılmaz, ancak çoğu durumda bu diller için oldukça iyi çalışır.

Obj-C ne olacak? Unut gitsin! Obj-C için ölü sıyırma yoktur. Obj-C, çalışma zamanı özellikli bir dil olduğundan, derleyici derleme sırasında bir sembolün gerçekten kullanımda olup olmadığını söyleyemez. Örneğin, doğrudan referans veren bir kod yoksa bir Obj-C sınıfı kullanılmaz, değil mi? Yanlış! Sınıf adı içeren bir dizeyi dinamik olarak oluşturabilir, bu ad için bir sınıf işaretçisi isteyebilir ve sınıfı dinamik olarak ayırabilirsiniz. Örneğin,

MyCoolClass * mcc = [[MyCoolClass alloc] init];

Ayrıca yazabilirim

NSString * cname = @"CoolClass";
NSString * cnameFull = [NSString stringWithFormat:@"My%@", cname];
Class mmcClass = NSClassFromString(cnameFull);
id mmc = [[mmcClass alloc] init];

Her iki durumda mmcda "MyCoolClass" sınıfının bir nesnesine bir başvurudır, ancak ikinci kod örneğinde bu sınıfa doğrudan başvuru yoktur (hatta statik bir dize olarak sınıf adı bile yoktur). Her şey sadece çalışma zamanında olur. Ve bu sınıflar olsa var olan aslında gerçek semboller. Gerçek semboller bile olmadıkları için kategoriler için daha da kötüdür.

Dolayısıyla, yüzlerce nesneye sahip statik bir kütüphaneniz varsa, ancak ikili dosyalarınızın çoğunun bunlardan sadece birkaçına ihtiyacı varsa, yukarıdaki çözümleri (1) ila (4) kullanmamayı tercih edebilirsiniz. Aksi takdirde, çoğu kullanılmasa bile, tüm bu sınıfları içeren çok büyük ikili dosyalar ile sonuçlanırsınız. Sınıflar için özel sembollere gerek yoktur, çünkü sınıflar gerçek sembollere sahiptir ve doğrudan referansta bulunduğunuz sürece (ikinci kod örneğinde olduğu gibi), bağlayıcı kullanımlarını oldukça iyi tanımlayacaktır. Ancak kategoriler için, yalnızca gerçekten ihtiyacınız olan kategorileri dahil etmeyi mümkün kıldığı için çözümü (5) düşünün.

Örneğin, NSData için bir kategori istiyorsanız, örneğin bir sıkıştırma / açma yöntemi eklemek isterseniz, bir başlık dosyası oluşturursunuz:

// NSData+Compress.h
@interface NSData (Compression)
    - (NSData *)compressedData;
    - (NSData *)decompressedData;
@end

void import_NSData_Compression ( );

ve bir uygulama dosyası

// NSData+Compress
@implementation NSData (Compression)
    - (NSData *)compressedData 
    {
        // ... magic ...
    }

    - (NSData *)decompressedData
    {
        // ... magic ...
    }
@end

void import_NSData_Compression ( ) { }

Şimdi kodunuzdaki herhangi bir yerin import_NSData_Compression()çağrıldığından emin olun . Nerede çağrıldığı veya ne sıklıkta çağrıldığı önemli değil. Aslında gerçekten çağrılmak zorunda değil, linker düşünürse yeterlidir. Örneğin, aşağıdaki kodu projenizin herhangi bir yerine koyabilirsiniz:

__attribute__((used)) static void importCategories ()
{
    import_NSData_Compression();
    // add more import calls here
}

importCategories()Kodunuzu hiç aramak zorunda değilsiniz , öznitelik derleyici ve bağlayıcıyı çağrılsa bile çağrıldığına inandırır.

Ve son bir ipucu: Son bağlantı çağrısına
eklerseniz -whyload, bağlayıcı, kullanım günlüğünde hangi kitaplığın hangi nesne dosyasından yüklendiğini hangi sembolün kullanıldığından yazdırır. Yalnızca kullanımda dikkate alınan ilk sembolü yazdıracaktır, ancak bu nesne dosyasının kullanımındaki tek simge olmak zorunda değildir.


1
Bahsettiğiniz için teşekkür ederiz, linker'ın -whyloadneden bir şey yaptığını hata ayıklamaya çalışmak oldukça zor olabilir!
Ben S

'De bir seçenek Dead Code Strippingvar Build Settings>Linking. O aynı şey mi -dead_stripeklendi Other Linker Flags?
Xiao

1
@Sean Evet, aynı. Her yapı ayarı için var olan "Hızlı Yardım" ı okuyunuz, cevap tam burada: postimg.org/image/n7megftnr/full
Mecki

@Mecki Teşekkürler. Kurtulmaya çalıştım -ObjC, bu yüzden hackini denedim ama şikayet ediyor "import_NSString_jsonObject()", referenced from: importCategories() in main.o ld: symbol(s) not found. Ben koymak import_NSString_jsonObjectadında benim gömülü Çerçevede Utilityve ekleme #import <Utility/Utility.h>ile __attribute__Sesimin sonunda açıklamada AppDelegate.h.
Xiao

@Sean Bağlayıcı sembolü bulamazsa, sembolü içeren statik kitaplığa bağlanmıyorsunuzdur. Sadece ah dosyasını bir çerçeveden içe aktarmak çerçeveye Xcode bağlantısı yapmaz. Çerçeve, çerçeve oluşturma aşamasıyla bağlantıda açıkça bağlantılı olmalıdır. Bağlama sorununuz için kendi sorunuzu açmak isteyebilirsiniz, yorumlara yanıt vermek hantaldır ve ayrıca derleme günlüğü çıktısı gibi bilgiler veremezsiniz.
Mecki

24

Bu sorun LLVM'de giderilmiştir . Düzeltme, LLVM 2.9'un bir parçası olarak gönderilir. Düzeltmeyi içeren ilk Xcode sürümü, LLVM 3.0 ile birlikte Xcode 4.2 gönderisidir. XCode 4.2 ile çalışırken veya kullanımına artık gerek yoktur-all_load-force_load -ObjC .


Bundan emin misin? LLVM 3.1 ile derleyen Xcode 4.3.2 kullanarak bir iOS projesi üzerinde çalışıyorum ve bu hala benim için bir sorundu.
Ashley Mills

Tamam, bu biraz kesin değildi. -ObjCBayrak hala ihtiyaç vardır ve her zaman olacaktır. Çözüm -all_loadveya kullanımı oldu -force_load. Ve artık buna gerek yok. Yukarıdaki cevabımı düzelttim.
tonklon

-All_load bayrağını eklemenin herhangi bir dezavantajı var mı (gereksiz olsa bile)? Derleme / başlatma süresini herhangi bir şekilde etkiler mi?
ZS

Xcode Sürüm 4.5 (4G182) ile çalışıyorum ve -ObjC bayrağı, Objective C çalışma zamanı derinliklerine benzeyen içine kullanmaya çalışıyorum 3. taraf bağımlılıktan tanınmayan seçici hatamı taşır: "- [__ NSArrayM haritası :]: tanınmayan seçici örneğe gönderildi ... ". Herhangi bir ipucu var mı?
Robert Atkins

16

Statik kitaplığınızı derlerken bu sorunu tamamen çözmek için yapmanız gerekenler:

Xcode Derleme Ayarlarına gidin ve Tek Nesne Ön Bağlantısı Gerçekleştir'i EVET olarak veya GENERATE_MASTER_OBJECT_FILE = YESderleme yapılandırma dosyanızda ayarlayın.

Varsayılan olarak, bağlayıcı her .m dosyası için bir .o dosyası oluşturur. Böylece kategoriler farklı .o dosyaları alır. Bağlayıcı statik bir kütüphane .o dosyalarına baktığında, sınıf başına tüm sembollerin bir dizinini oluşturmaz (Çalışma zamanı, ne olduğu önemli değildir).

Bu yönerge, bağlayıcıdan tüm nesneleri birlikte büyük bir .o dosyasına paketlemesini ister ve bu sayede statik kütüphaneyi işleyen bağlayıcıyı tüm sınıf kategorilerini endekslemeye zorlar.

Umarım bu açıklığa kavuşur.


Bu, bağlantı hedefine -ObjC eklemek zorunda kalmadan benim için düzeltildi.
Matthew Crenshaw

BlocksKit kütüphanesinin en son sürümüne güncelledikten sonra , sorunu düzeltmek için bu ayarı kullanmak zorunda kaldım (zaten -ObjC bayrağı kullanıyordum ama yine de sorunu görüyorum).
rakmoh

1
Aslında cevabınız tam olarak doğru değil. Ben "aynı sınıfın tüm kategorileri bir .o dosyasına birlikte paketlemek için sormak istemiyorum", o dışarıdan statik bir kütüphane oluşturmadan önce tüm nesne dosyalarını (.o) tek bir büyük nesne dosyasına bağlamak için linker sormak onları / o. Kütüphaneden herhangi bir sembol referans alındığında, tüm semboller yüklenir. Ancak, herhangi bir sembole başvurulmazsa (örneğin kütüphanede yalnızca kategoriler varsa işe yaramazsa) bu çalışmaz.
Mecki

NSData gibi mevcut sınıflara kategoriler eklerseniz bunun işe yarayacağını sanmıyorum.
Bob Whiteman

Ben de mevcut sınıflara kategori ekleme konusunda sorun yaşıyorum. Eklentim çalışma zamanında bunları tanıyamıyor.
David Dunham

9

Statik kütüphane bağlama tartışması ortaya çıktığında nadiren bahsedilen faktörlerden biri , kategorileri kendilerini yapı aşamalarına dahil etmeniz gerektiğidir-> dosyaları kopyalayın ve statik kütüphanenin kaynaklarını derleyin .

Apple ayrıca bu gerçeği son zamanlarda yayınlanan iOS'ta Statik Kütüphaneleri Kullanma'da da vurgulamıyor .

Ben -objC ve -all_load vb her türlü varyasyonları deneyerek bir gün geçirdim .. ama hiçbir şey çıktı .. bu soru bu sorunu dikkatime getirdi. (beni yanlış anlamayın .. -objC şeyler hala yapmak zorunda .. ama bundan daha fazlası).

Ayrıca her zaman bana yardımcı olan başka bir eylem her zaman ilk önce kendi dahil statik kitaplığı oluşturmak olduğunu .. sonra ben ekleyerek uygulama oluşturmak ..


-1

Muhtemelen statik kütüphanenizin "herkese açık" başlığında kategoriye sahip olmanız gerekir: #import "MyStaticLib.h"

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.