Kategorie celu-C w bibliotece statycznej

153

Czy możesz mi pomóc, jak poprawnie połączyć bibliotekę statyczną z projektem iPhone'a. Używam projektu biblioteki statycznej dodanego do projektu aplikacji jako bezpośredniej zależności (cel -> ogólne -> bezpośrednie zależności) i wszystko działa OK, ale kategorie. Kategoria zdefiniowana w bibliotece statycznej nie działa w aplikacji.

Więc moje pytanie brzmi: jak dodać bibliotekę statyczną z niektórymi kategoriami do innego projektu?

I ogólnie, jakie są najlepsze praktyki dotyczące używania w kodzie projektu aplikacji z innych projektów?

Vladimir
źródło
1
cóż, znalazłem kilka odpowiedzi i wygląda na to, że na to pytanie już odpowiedziano (przepraszam, że nie trafiłem na stackoverflow.com/questions/932856/… )
Vladimir

Odpowiedzi:

228

Rozwiązanie: od wersji Xcode 4.2 wystarczy przejść do aplikacji łączącej się z biblioteką (a nie samej biblioteki) i kliknąć projekt w Nawigatorze projektu, kliknąć element docelowy aplikacji, a następnie utworzyć ustawienia, a następnie wyszukać „Inne Linker Flags ”, kliknij przycisk + i dodaj„ -ObjC ”. „-all_load” i „-force_load” nie są już potrzebne.

Szczegóły: znalazłem odpowiedzi na różnych forach, blogach i w dokumentach Apple. Teraz spróbuję zrobić krótkie podsumowanie moich poszukiwań i eksperymentów.

Problem został spowodowany przez (cytat z Apple Technical Q&A QA1490 https://developer.apple.com/library/content/qa/qa1490/_index.html ):

Cel-C nie definiuje symboli konsolidatora dla każdej funkcji (lub metody w celu-C) - zamiast tego symbole konsolidatora są generowane tylko dla każdej klasy. Jeśli rozszerzasz wcześniej istniejącą klasę o kategorie, konsolidator nie wie, aby skojarzyć kod wynikowy implementacji klasy podstawowej z implementacją kategorii. Zapobiega to odpowiadaniu obiektom utworzonym w wynikowej aplikacji na selektor zdefiniowany w kategorii.

I ich rozwiązanie:

Aby rozwiązać ten problem, biblioteka statyczna powinna przekazać opcję -ObjC do konsolidatora. Ta flaga powoduje, że konsolidator ładuje każdy plik obiektowy w bibliotece, która definiuje klasę lub kategorię Objective-C. Chociaż ta opcja zazwyczaj skutkuje większym plikiem wykonywalnym (ze względu na dodatkowy kod obiektowy załadowany do aplikacji), pozwoli to na pomyślne utworzenie efektywnych bibliotek statycznych Objective-C, które zawierają kategorie w istniejących klasach.

i jest też zalecenie w FAQ rozwoju iPhone'a:

Jak połączyć wszystkie klasy Objective-C w bibliotece statycznej? Ustaw ustawienie kompilacji innych flag konsolidatora na -ObjC.

i opisy flag:

- all_load Ładuje wszystkich członków statycznych bibliotek archiwów.

- ObjC Ładuje wszystkich członków statycznych bibliotek archiwów, które implementują klasę lub kategorię Objective-C.

- force_load (path_to_archive) Ładuje wszystkich członków określonej biblioteki archiwum statycznego. Uwaga: -all_load wymusza załadowanie wszystkich członków wszystkich archiwów. Ta opcja umożliwia kierowanie na określone archiwum.

* możemy użyć force_load, aby zmniejszyć rozmiar binarny aplikacji i uniknąć konfliktów, które all_load może powodować w niektórych przypadkach.

Tak, działa z plikami * .a dodanymi do projektu. Jednak miałem problemy z dodaniem projektu lib jako bezpośredniej zależności. Ale później odkryłem, że to moja wina - projekt zależności bezpośredniej prawdopodobnie nie został poprawnie dodany. Kiedy go usunę i dodaję ponownie, wykonując kroki:

  1. Przeciągnij i upuść plik projektu lib w projekcie aplikacji (lub dodaj go za pomocą opcji Projekt-> Dodaj do projektu…).
  2. Kliknij strzałkę na ikonie projektu lib - pokazana nazwa pliku mylib.a, przeciągnij ten plik mylib.a i upuść go do grupy Target -> Link Binary With Library.
  3. Otwórz informacje o celu na pierwszej stronie (Ogólne) i dodaj moją bibliotekę do listy zależności

potem wszystko działa OK. W moim przypadku wystarczyła flaga „-ObjC”.

Interesował mnie również pomysł z bloga http://iphonedevelopmentexperiences.blogspot.com/2010/03/categories-in-static-library.html . Autor twierdzi, że może używać kategorii z biblioteki bez ustawiania opcji -all_load lub -ObjC. Po prostu dodaje do kategorii h / m pliki pusty interfejs / implementację klasy fikcyjnej, aby zmusić linker do użycia tego pliku. I tak, ta sztuczka działa.

Ale autor powiedział również, że nawet nie utworzył instancji obiektu zastępczego. Mm… Jak odkryłem, powinniśmy wprost nazwać jakiś „prawdziwy” kod z pliku kategorii. Powinna więc zostać wywołana przynajmniej funkcja klasy. I nawet nie potrzebujemy atrapy klasy. Pojedyncza funkcja c robi to samo.

Więc jeśli napiszemy pliki lib jako:

// 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

i jeśli wywołamy useMyLib (); w dowolnym miejscu projektu aplikacji, w dowolnej klasie możemy użyć metody kategorii logSelf;

[self logSelf];

I więcej blogów na ten temat:

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

Vladimir
źródło
8
Wydaje się, że od tego czasu notatka techniczna firmy Apple została zmodyfikowana i brzmi: „Aby rozwiązać ten problem, łączenie docelowe względem biblioteki statycznej musi przekazać opcję -ObjC do konsolidatora”. co jest przeciwieństwem tego, co przytoczono powyżej. Właśnie potwierdziliśmy, że przy łączeniu aplikacji należy uwzględnić, a nie samą bibliotekę.
Ken Aspeslagh
Zgodnie z dokumentem developer.apple.com/library/mac/#qa/qa1490/_index.html powinniśmy użyć flagi -all_load lub -force_load. Jak wspomniano, linker ma błąd w 64-bitowej aplikacji na Maca i aplikacji na iPhone'a. „Ważne: w przypadku aplikacji 64-bitowych i aplikacji na system iPhone OS istnieje błąd konsolidatora, który uniemożliwia -ObjC ładowanie plików obiektów z bibliotek statycznych, które zawierają tylko kategorie i nie zawierają klas. Obejściem problemu jest użycie flag -all_load lub -force_load”.
Robin
2
@Ken Aspelagh: Dzięki, miałem ten sam problem. Flagi -ObjC i -all_load należy dodać do samej aplikacji , a nie do biblioteki.
titaniumdecoy
3
Świetna odpowiedź, chociaż nowicjusze powinni zauważyć, że jest ono nieaktualne. Sprawdź odpowiedź tonklona stackoverflow.com/a/9224606/322748 (all_load / force_load nie są już potrzebne)
Jay Peyer,
Utknąłem w tych rzeczach przez prawie pół godziny i metodą prób i błędów po prostu to zrozumiałem. W każdym razie dzięki. Ta odpowiedź jest warta +1 i masz to !!!
Deepukjayan,
118

Odpowiedź Vladimira jest właściwie całkiem dobra, jednak chciałbym tutaj podać trochę więcej podstawowej wiedzy. Może któregoś dnia ktoś znajdzie moją odpowiedź i uzna ją za pomocną.

Kompilator przekształca pliki źródłowe (.c, .cc, .cpp, .m) na pliki obiektowe (.o). Istnieje jeden plik obiektowy na plik źródłowy. Pliki obiektów zawierają symbole, kod i dane. Pliki obiektowe nie są bezpośrednio używane przez system operacyjny.

Teraz podczas budowania biblioteki dynamicznej (.dylib), frameworka, ładowalnego pakietu (.bundle) lub wykonywalnego pliku binarnego, te pliki obiektowe są łączone ze sobą przez konsolidator w celu utworzenia czegoś, co system operacyjny uważa za „użyteczne”, np. Coś, co może bezpośrednio załadować do określonego adresu pamięci.

Jednak podczas budowania biblioteki statycznej wszystkie te pliki obiektowe są po prostu dodawane do dużego pliku archiwum, stąd rozszerzenie bibliotek statycznych (.a dla archiwum). Zatem plik .a to nic innego jak archiwum plików obiektowych (.o). Pomyśl o archiwum TAR lub archiwum ZIP bez kompresji. Po prostu łatwiej jest skopiować pojedynczy plik .a niż całą masę plików .o (podobnie jak w Javie, gdzie pakujesz pliki .class do archiwum .jar w celu łatwej dystrybucji).

Podczas łączenia pliku binarnego z biblioteką statyczną (= archiwum), konsolidator otrzyma tablicę wszystkich symboli w archiwum i sprawdzi, do których z tych symboli odwołują się pliki binarne. Tylko pliki obiektowe zawierające symbole, do których istnieją odniesienia, są w rzeczywistości ładowane przez konsolidator i są uwzględniane w procesie łączenia. Np. Jeśli twoje archiwum ma 50 plików obiektowych, ale tylko 20 zawiera symbole używane przez plik binarny, tylko tych 20 jest ładowanych przez konsolidator, pozostałe 30 są całkowicie ignorowane w procesie łączenia.

Działa to całkiem dobrze w przypadku kodu C i C ++, ponieważ języki te starają się robić jak najwięcej w czasie kompilacji (chociaż C ++ ma również pewne funkcje tylko w czasie wykonywania). Jednak Obj-C to inny rodzaj języka. Obj-C w dużym stopniu zależy od funkcji środowiska uruchomieniowego, a wiele funkcji Obj-C to w rzeczywistości funkcje tylko w czasie wykonywania. Klasy Obj-C w rzeczywistości mają symbole porównywalne z funkcjami C lub globalnymi zmiennymi C (przynajmniej w obecnym środowisku wykonawczym Obj-C). Konsolidator może sprawdzić, czy istnieje odwołanie do klasy, czy nie, więc może określić, która klasa jest używana, czy nie. Jeśli używasz klasy z pliku obiektowego w bibliotece statycznej, ten plik obiektowy zostanie załadowany przez konsolidator, ponieważ konsolidator widzi używany symbol. Kategorie są funkcją tylko w czasie wykonywania, kategorie nie są symbolami, takimi jak klasy lub funkcje, a to oznacza również, że konsolidator nie może określić, czy kategoria jest używana, czy nie.

Jeśli konsolidator ładuje plik obiektowy zawierający kod Obj-C, wszystkie jego części Obj-C są zawsze częścią etapu łączenia. Więc jeśli plik obiektowy zawierający kategorie jest ładowany, ponieważ dowolny jego symbol jest uważany za „używany” (czy to klasa, czy to funkcja, czy to zmienna globalna), kategorie są również ładowane i będą dostępne w czasie wykonywania . Jednak jeśli sam plik obiektowy nie zostanie załadowany, kategorie w nim zawarte nie będą dostępne w czasie wykonywania. Plik obiektowy zawierający tylko kategorie nigdy nie jest ładowany, ponieważ nie zawiera symboli, które konsolidator kiedykolwiek uznałby za „w użyciu”. I to jest cały problem tutaj.

Zaproponowano kilka rozwiązań i teraz, gdy już wiesz, jak to wszystko gra razem, spójrzmy jeszcze raz na proponowane rozwiązanie:

  1. Jednym z rozwiązań jest dodanie -all_loaddo wywołania konsolidatora. Co właściwie zrobi ta flaga konsolidatora? Właściwie to mówi linkerowi, co następuje: „ Załaduj wszystkie pliki obiektowe wszystkich archiwów, niezależnie od tego, czy widzisz jakiś używany symbol, czy nie .” Oczywiście to zadziała, ale może również dać dość duże pliki binarne.

  2. Innym rozwiązaniem jest dodanie -force_loaddo wywołania konsolidatora, w tym ścieżki do archiwum. Ta flaga działa dokładnie tak samo -all_load, ale tylko dla określonego archiwum. Oczywiście to również zadziała.

  3. Najpopularniejszym rozwiązaniem jest dodanie -ObjCdo wywołania konsolidatora. Co właściwie zrobi ta flaga konsolidatora? Ta flaga mówi konsolidatorowi " Załaduj wszystkie pliki obiektów ze wszystkich archiwów, jeśli zobaczysz, że zawierają one kod Obj-C ". „Każdy kod Obj-C” obejmuje kategorie. To również zadziała i nie wymusi ładowania plików obiektowych, które nie zawierają kodu Obj-C (są one nadal ładowane tylko na żądanie).

  4. Innym rozwiązaniem jest dość nowe ustawienie kompilacji Xcode Perform Single-Object Prelink. Co zrobi to ustawienie? Jeśli ta opcja jest włączona, wszystkie pliki obiektowe (pamiętaj, że jest jeden na plik źródłowy) są łączone razem w jeden plik obiektowy (to nie jest prawdziwe łączenie, stąd nazwa PreLink ) i ten pojedynczy plik obiektowy (czasami nazywany także „obiektem głównym plik ”) jest następnie dodawany do archiwum. Jeśli teraz jakikolwiek symbol głównego pliku obiektowego jest uważany za używany, cały główny plik obiektowy jest uważany za używany, a zatem wszystkie jego części Objective-C są zawsze ładowane. A ponieważ klasy są zwykłymi symbolami, wystarczy użyć jednej klasy z takiej biblioteki statycznej, aby uzyskać również wszystkie kategorie.

  5. Ostatnim rozwiązaniem jest sztuczka, którą Vladimir dodał na samym końcu swojej odpowiedzi. Umieść „ fałszywy symbol ” w dowolnym pliku źródłowym, deklarując tylko kategorie. Jeśli chcesz użyć którejkolwiek z kategorii w czasie wykonywania, upewnij się, że w jakiś sposób odwołujesz się do fałszywego symbolu w czasie kompilacji, ponieważ powoduje to, że plik obiektowy jest ładowany przez konsolidator, a tym samym cały kod Obj-C w nim. Np. Może to być funkcja z pustym ciałem funkcji (która nie zrobi nic po wywołaniu) lub może to być zmienna globalna, do której można uzyskać dostęp (np.intpo przeczytaniu lub napisaniu jest to wystarczające). W przeciwieństwie do wszystkich innych rozwiązań powyżej, to rozwiązanie przenosi kontrolę nad tym, które kategorie są dostępne w czasie wykonywania, na skompilowany kod (jeśli chce, aby były one połączone i dostępne, uzyskuje dostęp do symbolu, w przeciwnym razie nie uzyskuje dostępu do symbolu i konsolidator zignoruje) to).

To wszystko ludzie.

Och, czekaj, jest jeszcze jedna rzecz:
konsolidator ma opcję o nazwie -dead_strip. Co robi ta opcja? Jeśli konsolidator zdecyduje się załadować plik obiektowy, wszystkie symbole pliku obiektowego staną się częścią połączonego pliku binarnego, niezależnie od tego, czy są używane, czy nie. Np. Plik obiektowy zawiera 100 funkcji, ale tylko jedna z nich jest używana przez plik binarny, wszystkie 100 funkcji jest nadal dodawanych do pliku binarnego, ponieważ pliki obiektowe są albo dodawane jako całość, albo w ogóle nie są dodawane. Częściowe dodawanie pliku obiektowego nie jest zwykle obsługiwane przez konsolidatory.

Jednakże, jeśli powiesz konsolidatorowi "martwy pasek", konsolidator najpierw doda wszystkie pliki obiektowe do pliku binarnego, rozwiąże wszystkie odniesienia i na koniec przeskanuje plik binarny w poszukiwaniu symboli nieużywanych (lub używanych tylko przez inne symbole nie w posługiwać się). Wszystkie symbole, które nie są używane, są następnie usuwane w ramach etapu optymalizacji. W powyższym przykładzie 99 nieużywanych funkcji zostało ponownie usuniętych. Jest to bardzo przydatne, jeśli używasz opcji takich jak -load_all, -force_loadlub Perform Single-Object Prelinkponieważ te opcje mogą w niektórych przypadkach łatwo znacznie zwiększyć rozmiary binarne, a martwe usuwanie usunie nieużywany kod i dane ponownie.

Dead stripping działa bardzo dobrze w przypadku kodu C (np. Nieużywane funkcje, zmienne i stałe są usuwane zgodnie z oczekiwaniami), a także działa całkiem dobrze w C ++ (np. Nieużywane klasy są usuwane). Nie jest doskonały, w niektórych przypadkach niektóre symbole nie są usuwane, mimo że byłoby w porządku, aby je usunąć, ale w większości przypadków działa całkiem dobrze w tych językach.

A co z Obj-C? Zapomnij o tym! Nie ma martwego strippingu dla Obj-C. Ponieważ Obj-C jest językiem funkcji środowiska uruchomieniowego, kompilator nie może powiedzieć w czasie kompilacji, czy symbol jest rzeczywiście używany, czy nie. Np. Klasa Obj-C nie jest używana, jeśli nie ma bezpośredniego odniesienia do niej, prawda? Źle! Możesz dynamicznie zbudować ciąg zawierający nazwę klasy, zażądać wskaźnika klasy dla tej nazwy i dynamicznie przydzielić klasę. Np. Zamiast

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

Mógłbym też pisać

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

W obu przypadkach mmcjest to odniesienie do obiektu klasy „MyCoolClass”, ale w drugim przykładzie kodu nie ma bezpośredniego odniesienia do tej klasy (nawet nazwa klasy jako ciąg statyczny). Wszystko dzieje się tylko w czasie wykonywania. I to pomimo tego, że klasy są w rzeczywistości prawdziwymi symbolami. Jeszcze gorzej jest z kategoriami, ponieważ nie są one nawet prawdziwymi symbolami.

Więc jeśli masz bibliotekę statyczną z setkami obiektów, ale większość plików binarnych potrzebuje tylko kilku z nich, możesz nie chcieć używać powyższych rozwiązań (1) do (4). W przeciwnym razie otrzymasz bardzo duże pliki binarne zawierające wszystkie te klasy, mimo że większość z nich nigdy nie jest używana. W przypadku klas zwykle nie potrzebujesz żadnego specjalnego rozwiązania, ponieważ klasy mają prawdziwe symbole i tak długo, jak odwołujesz się do nich bezpośrednio (nie jak w drugim przykładzie kodu), konsolidator samodzielnie zidentyfikuje ich użycie. Jednak w przypadku kategorii rozważ rozwiązanie (5), ponieważ umożliwia ono uwzględnienie tylko tych kategorii, których naprawdę potrzebujesz.

Np. Jeśli chcesz mieć kategorię dla NSData, np. Dodając do niej metodę kompresji / dekompresji, możesz utworzyć plik nagłówkowy:

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

void import_NSData_Compression ( );

i plik implementacji

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

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

void import_NSData_Compression ( ) { }

Teraz po prostu upewnij się, że import_NSData_Compression()wywoływane jest dowolne miejsce w kodzie . Nie ma znaczenia, gdzie jest nazywany ani jak często się go nazywa. Właściwie to wcale nie musi być wywoływane, wystarczy, że linker tak myśli. Np. Możesz umieścić następujący kod w dowolnym miejscu projektu:

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

Nie musisz nigdy wywoływać importCategories()swojego kodu, atrybut sprawi, że kompilator i linker uwierzą, że jest wywoływany, nawet jeśli tak nie jest.

I ostatnia wskazówka:
jeśli dodasz -whyloaddo końcowego wywołania łącza, konsolidator wydrukuje w dzienniku kompilacji, który plik obiektowy, z której biblioteki załadował z powodu używanego symbolu. Wyświetli tylko pierwszy symbol rozważany jako używany, ale niekoniecznie jest to jedyny symbol używany w tym pliku obiektowym.

Mecki
źródło
1
Dziękuję za wspomnienie -whyload, próba debugowania, dlaczego linker coś robi, może być dość trudna!
Ben S,
Istnieje opcja Dead Code Strippingw Build Settings>Linking. Czy to jest to samo, co -dead_stripdodane w Other Linker Flags?
Xiao
1
@Sean Tak, to jest to samo. Po prostu przeczytaj „ Szybką
Mecki
@Mecki Thanks. Próbowałem się go pozbyć -ObjC, więc próbowałem twojego hacka, ale narzeka "import_NSString_jsonObject()", referenced from: importCategories() in main.o ld: symbol(s) not found. Umieściłem import_NSString_jsonObjectw moim osadzonym Framework o nazwie Utilityi dodaję #import <Utility/Utility.h>z __attribute__instrukcją na końcu mojego AppDelegate.h.
Xiao
@Sean Jeśli konsolidator nie może znaleźć symbolu, nie tworzysz połączenia z biblioteką statyczną, która zawiera symbol. Samo zaimportowanie pliku ah z frameworka nie spowoduje utworzenia linku Xcode do frameworka. Framework musi być wyraźnie powiązany z fazą tworzenia połączenia z frameworkiem. Możesz otworzyć własne pytanie dotyczące problemu z łączeniem, odpowiadanie w komentarzach jest uciążliwe, a także nie możesz podać informacji, takich jak dane wyjściowe dziennika kompilacji.
Mecki
24

Ten problem został rozwiązany w LLVM . Poprawka jest dostarczana jako część LLVM 2.9. Pierwsza wersja Xcode zawierająca poprawkę to Xcode 4.2 dostarczany z LLVM 3.0. Użycie -all_loadlub -force_loadnie jest już potrzebne podczas pracy z XCode 4.2 -ObjC jest nadal potrzebne.

tonklon
źródło
Jesteś tego pewien? Pracuję nad projektem iOS przy użyciu Xcode 4.3.2, kompiluję z LLVM 3.1 i nadal był to dla mnie problem.
Ashley Mills,
Ok, to było trochę nieprecyzyjne. -ObjCFlaga jest nadal potrzebne i zawsze będzie. Obejście polegało na użyciu -all_loadlub -force_load. I to już nie jest potrzebne. Poprawiłem odpowiedź powyżej.
tonklon
Czy jest jakaś wada dołączenia flagi -all_load (nawet jeśli jest niepotrzebna)? Czy ma to jakikolwiek wpływ na czas kompilacji / uruchomienia?
ZS
Pracuję z Xcode w wersji 4.5 (4G182), a flaga -ObjC przenosi mój nierozpoznany błąd selektora z zależności od strony trzeciej, której próbuję użyć, do tego, co wygląda jak głębia środowiska wykonawczego Objective C: "- [__ NSArrayM map :]: nierozpoznany selektor wysłany do instancji ... ”. Jakieś wskazówki?
Robert Atkins,
16

Oto, co musisz zrobić, aby całkowicie rozwiązać ten problem podczas kompilowania biblioteki statycznej:

Przejdź do ustawień kompilacji Xcode i ustaw opcję Perform Single-Object Prelink na YES lub GENERATE_MASTER_OBJECT_FILE = YESw pliku konfiguracyjnym kompilacji.

Domyślnie konsolidator generuje plik .o dla każdego pliku .m. Dlatego kategorie otrzymują różne pliki .o. Kiedy konsolidator patrzy na pliki .o biblioteki statycznej, nie tworzy indeksu wszystkich symboli na klasę (Runtime zrobi, nie ma znaczenia co).

Ta dyrektywa poprosi konsolidator o spakowanie wszystkich obiektów razem w jeden duży plik .o i przez to zmusi konsolidator, który przetwarza bibliotekę statyczną, aby uzyskać indeks wszystkich kategorii klas.

Mam nadzieję, że to wyjaśnia.

amosel
źródło
To naprawiło problem bez konieczności dodawania -ObjC do celu łączącego.
Matthew Crenshaw,
Po aktualizacji do najnowszej wersji biblioteki BlocksKit , musiałem użyć tego ustawienia, aby naprawić problem (używałem już flagi -ObjC, ale nadal widzę problem).
rakmoh
1
Właściwie twoja odpowiedź nie jest całkiem poprawna. Nie pytam konsolidatora o spakowanie wszystkich kategorii tej samej klasy razem w jeden plik .o, ale prosi konsolidatora o połączenie wszystkich plików obiektowych (.o) w jeden, duży plik obiektowy przed utworzeniem biblioteki statycznej z je / to. Po utworzeniu odniesienia do dowolnego symbolu z biblioteki, wszystkie symbole są ładowane. Jednak to nie zadziała, jeśli nie ma odniesienia do symbolu (np. Jeśli nie zadziała, jeśli w bibliotece są tylko kategorie).
Mecki
Nie sądzę, że to zadziała, jeśli dodasz kategorie do istniejących klas, takich jak NSData.
Bob Whiteman
Ja też mam problem z dodawaniem kategorii do istniejących klas. Moja wtyczka nie może ich rozpoznać w czasie wykonywania.
David Dunham
9

Jednym z czynników, o których rzadko się wspomina, gdy pojawia się dyskusja na temat łączenia bibliotek statycznych, jest fakt, że należy również uwzględnić same kategorie w fazach kompilacji -> kopiuj pliki i kompiluj źródła samej biblioteki statycznej .

Apple również nie podkreśla tego faktu w niedawno opublikowanych bibliotekach Using Static Libraries w iOS .

Spędziłem cały dzień próbując różnych odmian -objC i -all_load itd., Ale nic z tego nie wyszło ... to pytanie zwróciło moją uwagę na ten problem. (nie zrozum mnie źle… nadal musisz robić rzeczy -objC… ale to coś więcej niż tylko to).

Inną czynnością, która zawsze mi pomagała, jest to, że zawsze najpierw samodzielnie buduję dołączoną bibliotekę statyczną, a następnie buduję aplikację zamykającą.

abbood
źródło
-1

Prawdopodobnie musisz mieć kategorię w nagłówku „public” biblioteki statycznej: #import „MyStaticLib.h”

christo16
źródło