Pytanie Klasa X jest zaimplementowana zarówno w Y, jak i Z. Jeden z dwóch będzie użyty


Posiadam program "console" ("narzędzie"), który dynamicznie ładuje pakiet c w czasie wykonywania. Niektóre pliki pakietu dzielą klasy z tego samego środowiska, więc pojawia się komunikat "Klasa jest zaimplementowana w obu ..." do konsoli.

Nie przeszkadza to w pracy, ale posiadanie komunikatów na konsoli jest dość irytujące. Czy istnieje sposób, aby zapobiec ich wyrzuceniu tam? Czy istnieje sposób, aby pakiet mógł zostać zmieniony, aby nie kompilowały / nie łączyły tych samych klas?


12
2018-01-16 21:11


pochodzenie




Odpowiedzi:


Byłem już w tej łodzi i nie jest to dobra łódź. Spędziłem dużo czasu, inwestując w najlepszy możliwy sposób, aby uniknąć starć klasowych w czasie wykonywania. Rozwiązaniem było:

  1. Utwórz wstępny skrypt, który analizuje wszystkie @interface deklaracje w plikach nagłówkowych i zbiera wszystkie nazwy klas. Ten skrypt generuje nowy nagłówek zawierający coś podobnego do następującego:

    #define MyClass        MyClass_Target
    #define MyOtherClass   MyOtherClass_Target
    #define MyThirdClass   MyThirdClass_Target
    

    (oczywiście _Target sufiks jest ustawiany przez parametr kompilacji, który twój skrypt pre-build może zobaczyć i wykorzystać).

    Skrypt może być skryptem Perl lub Python, który po prostu skanuje każdy *.h plik wyodrębniający słowo po @interface.

  2. Skonfiguruj kompilację, aby automatycznie uwzględniała wygenerowany plik nagłówkowy, aby nie trzeba było ręcznie włączać wygenerowanego nagłówka do każdego pliku źródłowego.

  3. Jeśli twoje pakunki mają końcówki, dodaje dodatkowy krok złożoności, ale nadal można to zrobić. Utwórz kolejny skrypt, który zastąpi istniejący "Kompilator Nib". Ten program zasadniczo wykonuje tę samą zmianę nazwy klasy, ale dla stalówki (jest to dość łatwe, ponieważ pliki końcówki są XML). Nie pamiętam, gdzie to ustawić, ale w Xcode jest miejsce, które pozwala ci wybrać sposób kompilacji plików Nib. Twój skrypt kompilatora stalówki to w zasadzie wrapper, który zmienia nazwy klas w stalówce, a następnie wywołuje prawdziwy kompilator stalówki (który możesz dowiedzieć się, jak jest wywoływany przez przeglądanie dziennika budowy).

Czy to działa?

Tak, i działa zaskakująco dobrze, nawet w sytuacjach debugowania. Po znalezieniu punktu przerwania Xcode wyświetla nazwę klasy z sufiksem docelowym dzięki czemu wiesz, w którym pakiecie się znajdujesz, mimo że kod źródłowy pokazuje coś innego. "Napraw i kontynuuj" nadal działało, o ile pamiętam.

Ponadto, ponieważ zmiana nazwy klasy odbywa się tuż przed czasem kompilacji, nie ma ona wpływu na takie funkcje, jak wersjonowanie kodu źródłowego, interakcje z narzędziem Interface Builder itp.

Problemy

  • Dynamicznie generowane nazwy klas nie będą działać, np. Class obiekty zwrócone z NSClassFromString, chyba że kod zostanie powiadomiony o niezbędnym sufiksie.

  • Tak skomplikowana konfiguracja wymaga nieco konserwacji. Kiedy już go uruchomiłem, działało dobrze na nasze potrzeby, ale od czasu do czasu potrzebował poprawek, aby działało płynnie.


3
2018-04-27 04:36



Właśnie w to wpadłem. Miałem niewielką liczbę klas, więc zrobiłem to ręcznie. - didge


  • Jeśli są to różne implementacje, użyj unikalnego prefiksu.

  • Jeśli są to te same implementacje i po prostu wyeksportowane przez więcej niż jeden obraz, przekonfiguruj swoje cele, aby eksportować je tylko przez jeden.

Konkretnie:

Czy istnieje sposób, aby pakiet mógł zostać zmieniony, aby nie kompilowały / nie łączyły tych samych klas?

Umieść te udostępnione klasy w osobnym frameworku i nie kompiluj ich jako części pakietu - wystarczy połączyć pakiet ze strukturą udostępnianych rzeczy.


3
2018-04-27 05:10





Czy próbowałeś tylko dodawać nagłówki (@interfaces) wspólnych klas do pakietów (tak, aby kompilator wiedział o API), ale nie plików kodu (@implementations)?

Ponieważ łączysz pakiet, linker (ld) nie powinien narzekać, że nie może znaleźć implementacji danych klas - przekaże to zadanie dynamicznemu linkerowi (dyld), który uruchamia się po załadowaniu pakietu w programie głównym. dyld powinien następnie ustalić automagicznie wymagane referencje między pakietami i programem.


0
2018-01-16 22:17



Dodałem już .h do celu pakietów (a nie implementacji). Nie jest to problem w czasie kompilacji, jest to dziennik zgłaszany w czasie wykonywania, gdy załadowane są dwa moduły korzystające z tej samej klasy. - bugfixr


Jeśli tworzysz pakiet wtyczek, możesz pominąć -unefined dynamic_lookup jako inne znaczniki linkera i usunąć wszystkie biblioteki z wtyczki, które duplikują w obu (w głównym pliku binarnym i wtyczce)


0
2017-10-27 16:09