Случайны выбор дневника Раскрыть/свернуть полный список возможностей


Найдено 588 сообщений
Cообщения с меткой

вредные советы - Самое интересное в блогах

Следующие 30  »
inhanpoemogh

Intoxic - средство от паразитов

Понедельник, 12 Сентября 2016 г. 17:05 (ссылка)

bigimg (197x700, 84Kb)
Все началось с того, что у меня было регулярное недомогание.
Все началось с того, что у меня было регулярное недомогание.

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Из песочницы] 30 вредных советов для php-разработчиков

Среда, 07 Сентября 2016 г. 19:43 (ссылка)

Я не стал сильно заморачиваться и расписывать очевидные факты, но большинство моментов, которые меня пугают в коде, тут изложены. Я постарался сделать список особо лаконичным, чтобы вам не пришлось вчитываться, но и максимум понятным, чтобы даже новички поняли что так делать нельзя. В общем ниже список моих вредных советов, основанных на том, с чем я сталкиваюсь в повседневной жизни.







Итак поехали:




  1. Обязательно пишите вёрстку прямо в php-скриптах и выводите её только через echo (зачем-то же нужна эта конструкция языка).




  2. Старайтесь использовать как можно больше echo в ваших проектах, помните, что её придумали крутые разработчики языка, до которых вам далеко.




  3. Прописывайте параметры подключения к БД в каждом файле где это нужно, и нигде не храните инфу о том где и какие конфигурации прописаны — пусть все остальные развиваются до вашего уровня.




  4. Создавайте как можно больше подключений к БД в разных частях проекта, желательно чтобы многие из них вызывались одновременно, вообще создавайте новое подключение к БД при каждом запуске любой функции.




  5. Не используйте стандартные функции языка — пишите свои, они будут работать в 100 раз лучше и именно так, как вам нужно.




  6. Подключайте все файлы проекта в любом месте проекта даже если вам нужна всего одна функция.




  7. Используйте массив GLOBALS — без него вообще никак, разработчики языка придумали его для вашего удобства, а вот проблемы с закончившейся озушкой это проблемы сервера, а не языка.




  8. Вызывайте функции и используйте циклы прямо в верстке, это вывод информации, там без функций никак.




  9. Ни в коем случае не используйте mysql-параметры, пишите переменные $_GET, $_POST, прямо в запрос, чтобы не тратить лишнее процессорное время, оно для нас очень важно.




  10. Дублируйте один и тот же метод во всех классах каждый раз, когда он вам понадобится, забудьте про наследование это пережиток прошлого.




  11. Используйте только статические методы и свойства, не нужно создавать объекты, классы придуманы не для этого.




  12. Методы классов, работающих с БД должны возвращать РЕСУРС и никак по-другому, лучше используйте while каждый раз когда получаете данные от класса.




  13. Обязательно делайте sql-запросы в циклах, это очень важно, иначе как вы получите все записи из таблицы?




  14. Храните дату и время в полях типа varchar, потому-что поле datetime имеет какой-то свой странный формат.




  15. Создайте себе поле в таблице, где для каждой записи будете дописывать через
    все изменения с записью, и обязательно именно так. Ни в коем случае не создавайте отдельную таблицу логов, зачем нам лишний файл на диске.




  16. Не создавайте много ячеек в таблицах БД, лучше используйте seialize и забудьте про кодировку при сохранении, если unserialize каждый раз выдает ошибку, просто игнорируйте её.




  17. Вообще игнорируйте ВСЕ ошибки в проекте, выключите error_reporting — он только мешает, не будьте задротами.




  18. Никогда, слышите, никогда не проверяйте переменную на существование, просто выводите её прямо в шаблон, после пункта 17, Notice для вас уже не проблема.




  19. Пишите только так for($i=0; $icode>, потому-что считать количество элементов в массиве при каждой итерации это хорошо, а постинкремент работает намного быстрее, а кто говорит наоборот просто не знает о чем говорит. И перебирать большой массив нужно именно сначала, потому-что так быстрее.




  20. Не используйте парсинг ни в каком виде, это очень плохо, лучше скачивайте страницу целиком вместе с версткой и сохраняйте её в БД прямо как получили, не тратьте время на парсинг, тем более использование DomDocument очень замедляет проект, и его же еще учить нужно, а вам некогда — надо проект писать.




  21. Храните всю информацию о пользователях в одной таблице — данные для авторизации, анкетные данные, домашние адреса и телефоны, места работы, да вообще любую информацию храните в одной таблице и не забывайте про serialize




  22. Не используйте индексы и ключи в БД, и тем более связи между таблицами, это очень плохо.




  23. Никогда не используйте таблицы-справочники, лучше дублируйте все в одной колонке, тем более если колонка содержит большие и часто повторяющиеся данные.




  24. Вы слышали про стандарт именования функций и методов? Забудьте! Кто вообще придумал что в именах функций должна быть какая-то логика, да и функции с именами a(), b(), aa() намного короче вызывать.




  25. Делайте функции как можно больше, если программисту лень читать что делает функция — он плохой программист.




  26. Никогда и нигде не пишите комментарии, потому-что тру-прогерам они не нужны, в худшем случае можно написать коммент типа /*это функция a(), она принимает две переменные $a и $b*/ для совсем тупых.




  27. Функции должны принимать как можно больше параметров, делать с ними кучу самых разных действий и возвращать всегда непредсказуемый результат, чтобы всё-таки заставить прогеров прочитать их исходники.




  28. Так как мы уже решили не использовать наследование, повторно писать функции с других классов, то надо дополнить это еще и тем, что класс должен быть не меньше 1000 строк, и чем он больше, тем лучше.




  29. Для того чтобы получить по-настоящему большой класс, нужно для каждой скобочки выделять целую строчку, нужно обязательно создать очень много свойств класса, на всякий случай, а еще мы помним что ни в коем случае нельзя использовать стандартные функции php — всегда пишем свои.




  30. И последнее, допустим что вам нужен скрипт, у которого действия меняются в зависимости от даты (а вдруг), обязательно пишите эту дату прямо в скрипт, чтобы каждый раз заходить и исправлять её руками, чтобы всегда держать скрипт под контролем.



Спасибо за внимание!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/309450/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
lira_lara

«Если вы решили твердо самолет угнать на Запад…»

Четверг, 02 Сентября 2016 г. 02:23 (ссылка)


 


 Вредные советы для взрослых: «Если вы решили твердо самолет угнать на Запад…»


 


   


Вредные советы для взрослых: «Если вы решили твердо самолет угнать на Запад…»


 


 


Григорий Остер известен как автор «вредных советов» для детей. Однако некоторые из этих советов настолько «вредные», что даже удивляешься, как они попали в детскую книжку.


 


Если вас навек сплотили,


Озарили и ведут,


Не пытайтесь уклониться


От движенья к торжеству.


Все равно на труд поднимет


И на подвиг вдохновит


Вас великий и могучий,


И надежный наш оплот.


***


 


 


Главным делом жизни вашей


Может стать любой пустяк.


Надо только твердо верить,


Что важнее дела нет.


И тогда не помешает


Вам ни холод, ни жара,


Задыхаясь от восторга,


Заниматься чепухой.


***


 


 


Если ты весь мир насилья


Собираешься разрушить,


И при этом стать мечтаешь


Всем, не будучи ничем,


Смело двигайся за нами


По проложенной дороге,


Мы тебе дорогу эту


Можем даже уступить.


***


 


 


Если вы решили первым


Стать в рядах своих сограждан -


Никогда не догоняйте


Устремившихся вперед.


Через пять минут, ругаясь,


Побегут они обратно,


И тогда, толпу возглавив,


Вы помчитесь впереди.


***


 


 


Если вы решили твердо


Самолет угнать на Запад,


Но не можете придумать,


Чем пилотов напугать,


Почитайте им отрывки


Из сегодняшней газеты, -


И они в страну любую


Вместе с вами улетят.


***


 


 


Не бери чужое, если


На тебя глядят чужие.


Пусть они глаза закроют


Или выйдут на часок.


А своих чего бояться!


Про своих свои не скажут.


Пусть глядят. Хватай чужое


И тащи его к своим.


***


 


 


Дразниться лучше из окна,


С восьмого этажа.


Из танка тоже хорошо,


Когда крепка броня.


Но если хочешь довести


Людей до горьких слез,


Их безопаснее всего


По радио дразнить.


***


 


 


Если в кухне тараканы


Маршируют по столу,


И устраивают мыши


На полу учебный бой,


Значит, вам пора на время


Прекратить борьбу за мир,


И все силы ваши бросить


На борьбу за чистоту.


 


Из: Григорий Остер. Вредные советы.

Метки:   Комментарии (1)КомментироватьВ цитатник или сообщество
Троян_95

Вредные советы. 49 причин, почему не стоит ехать в Украину

Пятница, 05 Августа 2016 г. 14:46 (ссылка)

Это цитата сообщения Vsiaco Оригинальное сообщение

1. Не слушайте тех, кто говорит, что Украина – красивая страна. Они нагло врут! 



Вредные советы. 49 причин, почему не стоит ехать в Украину



Источник фото: blogger.com, автор – конфеткина. На фото: Бакотский залив.

Читать далее...
Метки:   Комментарии (3)КомментироватьВ цитатник или сообщество
Кейси_Кармен

25 «вредных» советов Григория Остера!

Пятница, 27 Мая 2016 г. 07:20 (ссылка)


совет (698x365, 277Kb) Самый «вредный» писатель детства Григорий Остер писал о том, что есть дети, которые делают всё наоборот. Всё, что им не скажешь, они вывернут наизнанку. Не потому, что они хотят разозлить родителей или воспитателей, а потому, что так живётся веселее.



Специально для них он составил целую книгу «вредных советов», следовать которым нужно с точностью до наоборот. Вот тогда и будет получаться всё правильно.



А совсем недавно ученые догадались, что, оказывается, и послушным детям нужны вредные советы. Они действуют на них как таблетка от глупости. Поэтому вредные советы рекомендуется читать всем детям — и послушным, и непослушным.



Советами Остера зачитывались все – это же целая энциклопедия детства, со всеми его хитростями и премудростями. 25 «вредных» советов, чтобы ещё раз вспомнить об этом чудесном времени или порадовать уже своих хулиганов:



0_8feb2_6ccaaed2_M.jpg (160x92, 23Kb)
Метки:   Комментарии (12)КомментироватьВ цитатник или сообщество
Ирцейс

Вредные советы: 7 популярных лайфхаков, которые НЕ работают

Пятница, 20 Мая 2016 г. 09:45 (ссылка)


Полезные советы просто переполнили Интернет — везде мы читаем о том, как продлить жизнь косметике и чем увлажнить лицо, если закончился крем.

3720816_soveti_po_makiyajy (640x442, 60Kb)

Но все ли лайфхаки действительно работают?

Читать далее



 



 

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Objective-C, static libraries, categories, -ObjC, боль…

Воскресенье, 15 Мая 2016 г. 04:00 (ссылка)

Не всем повезло писать приложения полностью на Swift, да и еще под ios 8+ онли. Много легаси на Objective-C, много зависимостей идет через статик либы, ни cocoapods, ни carthage, всё ручками. Мы же крутые девелоперы, поэтому строго следуем DRY и все реюзабельные вкусшянки выносим либо в отдельные проекты, либо в статик библиотеки. Сейчас рассмотрим случай, когда мы сделали классную статичную библиотечку с не менее прикольным апи, и хотели бы поделиться с товарищами по цеху внутри компании — на вики ресурсе/гите выложить архивчик с либой, хедерами и, конечно же, ридмиком где описан весь апи и как им пользоваться.



Для примера ради рассмотрим один класс + его категорию











На скриншоте у нас структура проекта, где класс + класс категория, всё просто. Собираем обычным образом, пишем readme.md с описанием апи и архивируем библиотеку. Всё круто, залили на вики, пацанам твитнули в slack/skype/etc и пошли себе за очередным кофе. Только присели обратно со свежесваренным кофе и курсор мышки почти достиг закладки на хабр, как в чаты посыпались какие-то логи, и все требуют вашего немедленного ответа, так как проблема в свежезарелизенной либе. Вас бросило в пот, ведь у вас тестовое покрытие 146%, всё на сто раз перепроверено. В это же самое время в чате уже в личку снова пишут тот же самый лог ошибки:



*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Deadpool guns]: unrecognized selector sent to instance 0x7ffecbc12df0'




После ознакомления с логом, причина ясна и до боли знакома когда часто работаешь со статик либами. Поняв проблему, вы уверенно вытираете пот со лба, открываете ранее отправленный readme.md и дописываете:



Don't forget to add '-ObjC' flag to 'Other Linker Flags' in Build Settins of Xcode's scheme.



После, обновили вики, снова всех оповестили и вроде всё успокоилось, месседжеры замолкли, кофе даже не успело остыть. «Ну сейчас точно никто меня не оставновит» — шепчет ваш внутренний голос и курсор мыши снова тянется к заветной закладке (ненене, только хабр!). От желанного тебя отделяет только клик по левой кнопке мыши, но тебя не покидает мысль: «Можно ли было избежать этой ошибки или как предотвратить ее в будущем?!». «Да к черту всё!» — воскликнул внутренний голос и курсор потянулся к Terminal.app.



otool -tV -arch x86_64 libDeadpool.a




выдает:



Archive : libDeadpool.a
libDeadpool.a(Deadpool+Guns.o):
(__TEXT,__text) section
-[Deadpool(Guns) guns]:
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 subq $0x10, %rsp
0000000000000008 leaq 0x71(%rip), %rax ## Objc cfstring ref: @"sword 2"
000000000000000f movd %rax, %xmm0
0000000000000014 leaq 0x45(%rip), %rax ## Objc cfstring ref: @"sword 1"
000000000000001b movd %rax, %xmm1
0000000000000020 punpcklqdq %xmm0, %xmm1 ## xmm1 = xmm1[0],xmm0[0]
0000000000000024 movdqa %xmm1, -0x10(%rbp)
0000000000000029 movq 0x70(%rip), %rdi ## Objc class ref: NSArray
0000000000000030 movq 0x91(%rip), %rsi ## Objc selector ref: arrayWithObjects:count:
0000000000000037 leaq -0x10(%rbp), %rdx
000000000000003b movl $0x2, %ecx
0000000000000040 callq *_objc_msgSend(%rip)
0000000000000046 addq $0x10, %rsp
000000000000004a popq %rbp
000000000000004b retq
libDeadpool.a(Deadpool.o):
(__TEXT,__text) section
-[Deadpool name]:
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 movq 0x1d(%rip), %rsi ## Objc selector ref: class
000000000000000b callq *_objc_msgSend(%rip)
0000000000000011 movq %rax, %rdi
0000000000000014 popq %rbp
0000000000000015 jmp _NSStringFromClass




хм, в самой либе все методы на месте, теперь посмотрим исходники приложения:



otool -tV -arch x86_64 DemoApp.app/DemoApp | grep Deadpool




выдает:



0000000100001ae8	movq	0x21f1(%rip), %rdi      ## Objc class ref: Deadpool
0000000100001af6 movq 0x1513(%rip), %r12 ## Objc message: +[Deadpool new]
-[Deadpool name]:




WTF! Окей гугл, где же все таки метод из категории?



гугл нам умело подсовывает ссылку на офф документацию эпла по этой как раз проблеме https://developer.apple.com/library/mac/qa/qa1490/_index.html, где беглый перевод говорит следующее:



The Linker



Когда си-программа скомпилирована, то каждый файл (.c) компилируется в так называемый «object file» (.o), который содержит реализацию функций и другую статичную информацию. После линкер собирает все эти файлы в один конечный файл — executable. И этот executable файл как раз и попадает внутрь нашей .app посредством Xcode.



Но когда source файл (.c) использует что либо, например функцию, что определено в другом файле (другой .c файл), тогда «undefined symbol» записывается в .o файл для этого участка кода. И на этапе сборки линкеру достаточно информации чтобы по «undefined symbol» понять откуда нужно вытащить недостающую вещь чтобы собрать конечный executable. Это описание для сборки UNIX static library.




Objective-C



Из-за динамической природы языка этот процесс в Objective-C немного усложенен, так как поиск реализации метода происходит только по факту обращения к этому методу. Objective-C не определяет вспомогательных symbols для методов линкеру, а только определяет symbols для классов. Например, в классе/файле main.o есть код:



[[FooClass alloc] initWithBar:nil]



то есть, FooClass это отдельный класс, в отдельном FooClass.o файле, так вот main.o будет только содержать «undefined symbol» для FooClass, но ни никаких дополнительных symbols для метода -initWithBar: в этом классе.



Так как категория это просто отдельный файл с методами, то у линкера нет совершенно никакой информации, что этот файл нужно слинковать, так как для методов не создаются вспомогательные линкеру «undefined symbol» штуки.




Так, вроде разобрались, еще раз посмотрим на байт код либы:



Archive : libDeadpool.a
libDeadpool.a(Deadpool+Guns.o):
(__TEXT,__text) section
-[Deadpool(Guns) guns]:
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 subq $0x10, %rsp
0000000000000008 leaq 0x71(%rip), %rax ## Objc cfstring ref: @"sword 2"
000000000000000f movd %rax, %xmm0
0000000000000014 leaq 0x45(%rip), %rax ## Objc cfstring ref: @"sword 1"
000000000000001b movd %rax, %xmm1
0000000000000020 punpcklqdq %xmm0, %xmm1 ## xmm1 = xmm1[0],xmm0[0]
0000000000000024 movdqa %xmm1, -0x10(%rbp)
0000000000000029 movq 0x70(%rip), %rdi ## Objc class ref: NSArray
0000000000000030 movq 0x91(%rip), %rsi ## Objc selector ref: arrayWithObjects:count:
0000000000000037 leaq -0x10(%rbp), %rdx
000000000000003b movl $0x2, %ecx
0000000000000040 callq *_objc_msgSend(%rip)
0000000000000046 addq $0x10, %rsp
000000000000004a popq %rbp
000000000000004b retq
libDeadpool.a(Deadpool.o):
(__TEXT,__text) section
-[Deadpool name]:
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 movq 0x1d(%rip), %rsi ## Objc selector ref: class
000000000000000b callq *_objc_msgSend(%rip)
0000000000000011 movq %rax, %rdi
0000000000000014 popq %rbp
0000000000000015 jmp _NSStringFromClass




Действительно, у нас скомпилировалось два файла Deadpool.o и Deadpool+Guns.o, так как второй файл это просто набор методов для первого, то линкер о нем ничего не знает и поэтому получаем эту ошибку только в рантайме.



Сразу первое решение — перенести категорию в файл основного класса. Да, это будет работать :) но для нас это не совсем удобно, так как мы привыкли все категории держать в отдельных папочках для порядка.



Другое решение. Тем, кто использует нашу либу, должны указать -ObjC флаг в «Other Linker Flags», этот флаг говорит линкеру загрузить всё всё всё из статичной либы. Ну, нам подходит это решение тем, что на нашей стороне ничего править не нужно. Но если подумать, если разработчик подключит кучу либ и только из-за нашей ему приходится добавлять этот флаг, то он может получить нехилое прибавление в весе для своего приложения (я так предполагаю).



А можно ли как то сказать линкеру, чтобы он собрал класс и его категории в один файл? Оказывается есть такое и название ему «Perform Single-Object Prelink» или «GENERATE_MASTER_OBJECT_FILE» в pbxproj файле. Правда происходит не просто объединение класса и его категории в единый файл, а все файлы проекта будут как единый «object file». Если это значение выставить в true, то мы должны получить поведение, которое хотим. Проверим.



Выставляем:







otool -tV -arch x86_64 libDeadpool.a




получаем:



Archive : libDeadpool.a
libDeadpool.a(libDeadpool.a-x86_64-master.o):
(__TEXT,__text) section
-[Deadpool(Guns) guns]:
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 subq $0x10, %rsp
0000000000000008 leaq 0x149(%rip), %rax ## Objc cfstring ref: @"sword 2"
000000000000000f movd %rax, %xmm0
0000000000000014 leaq 0x11d(%rip), %rax ## Objc cfstring ref: @"sword 1"
000000000000001b movd %rax, %xmm1
0000000000000020 punpcklqdq %xmm0, %xmm1 ## xmm1 = xmm1[0],xmm0[0]
0000000000000024 movdqa %xmm1, -0x10(%rbp)
0000000000000029 movq 0x270(%rip), %rdi ## Objc class ref: NSArray
0000000000000030 movq 0x259(%rip), %rsi ## Objc selector ref: arrayWithObjects:count:
0000000000000037 leaq -0x10(%rbp), %rdx
000000000000003b movl $0x2, %ecx
0000000000000040 callq *_objc_msgSend(%rip)
0000000000000046 addq $0x10, %rsp
000000000000004a popq %rbp
000000000000004b retq
-[Deadpool name]:
000000000000004c pushq %rbp
000000000000004d movq %rsp, %rbp
0000000000000050 movq 0x241(%rip), %rsi ## Objc selector ref: class
0000000000000057 callq *_objc_msgSend(%rip)
000000000000005d movq %rax, %rdi
0000000000000060 popq %rbp
0000000000000061 jmp _NSStringFromClass




Что и хотели, сейчас всё в одном файле. Убираем из приложения -ObjC и пересобираем с новой версией нашей библиотеки и смотрим:



otool -tV -arch x86_64 DemoApp.app/DemoApp | grep Deadpool




вывод:



0000000100001a70	movq	0x22c9(%rip), %rdi      ## Objc class ref: Deadpool
0000000100001a7e movq 0x158b(%rip), %r12 ## Objc message: +[Deadpool new]
-[Deadpool(Guns) guns]:
-[Deadpool name]:




Отлично. Сейчас можно обратно из readme.md удалять информацию о -ObjC флаге, смело открывать хабр и допивать, к сожалению, уже остывший кофе )



пс.



Проблема бородатая, давно ее решил, сейчас вот дошли руки написать и более подробно в этом разобраться )

Не уверен в идеальности решения, но мне помогло с этой проблемой, может кому будет интересно.



Полезные ссылки:



https://developer.apple.com/library/mac/qa/qa1490/_index.html

http://stackoverflow.com/questions/2567498/objective-c-categories-in-static-library



Original source: habrahabr.ru.

https://habrahabr.ru/post/283570/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Objective-C, static libraries, categories, -ObjC, боль…

Воскресенье, 15 Мая 2016 г. 04:00 (ссылка)

Не всем повезло писать приложения полностью на Swift, да и еще под ios 8+ онли. Много легаси на Objective-C, много зависимостей идет через статик либы, ни cocoapods, ни carthage, всё ручками. Мы же крутые девелоперы, поэтому строго следуем DRY и все реюзабельные вкусшянки выносим либо в отдельные проекты, либо в статик библиотеки. Сейчас рассмотрим случай, когда мы сделали классную статичную библиотечку с не менее прикольным апи, и хотели бы поделиться с товарищами по цеху внутри компании — на вики ресурсе/гите выложить архивчик с либой, хедерами и, конечно же, ридмиком где описан весь апи и как им пользоваться.



Для примера ради рассмотрим один класс + его категорию











На скриншоте у нас структура проекта, где класс + класс категория, всё просто. Собираем обычным образом, пишем readme.md с описанием апи и архивируем библиотеку. Всё круто, залили на вики, пацанам твитнули в slack/skype/etc и пошли себе за очередным кофе. Только присели обратно со свежесваренным кофе и курсор мышки почти достиг закладки на хабр, как в чаты посыпались какие-то логи, и все требуют вашего немедленного ответа, так как проблема в свежезарелизенной либе. Вас бросило в пот, ведь у вас тестовое покрытие 146%, всё на сто раз перепроверено. В это же самое время в чате уже в личку снова пишут тот же самый лог ошибки:



*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Deadpool guns]: unrecognized selector sent to instance 0x7ffecbc12df0'




После ознакомления с логом, причина ясна и до боли знакома когда часто работаешь со статик либами. Поняв проблему, вы уверенно вытираете пот со лба, открываете ранее отправленный readme.md и дописываете:



Don't forget to add '-ObjC' flag to 'Other Linker Flags' in Build Settins of Xcode's scheme.



После, обновили вики, снова всех оповестили и вроде всё успокоилось, месседжеры замолкли, кофе даже не успело остыть. «Ну сейчас точно никто меня не оставновит» — шепчет ваш внутренний голос и курсор мыши снова тянется к заветной закладке (ненене, только хабр!). От желанного тебя отделяет только клик по левой кнопке мыши, но тебя не покидает мысль: «Можно ли было избежать этой ошибки или как предотвратить ее в будущем?!». «Да к черту всё!» — воскликнул внутренний голос и курсор потянулся к Terminal.app.



otool -tV -arch x86_64 libDeadpool.a




выдает:



Archive : libDeadpool.a
libDeadpool.a(Deadpool+Guns.o):
(__TEXT,__text) section
-[Deadpool(Guns) guns]:
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 subq $0x10, %rsp
0000000000000008 leaq 0x71(%rip), %rax ## Objc cfstring ref: @"sword 2"
000000000000000f movd %rax, %xmm0
0000000000000014 leaq 0x45(%rip), %rax ## Objc cfstring ref: @"sword 1"
000000000000001b movd %rax, %xmm1
0000000000000020 punpcklqdq %xmm0, %xmm1 ## xmm1 = xmm1[0],xmm0[0]
0000000000000024 movdqa %xmm1, -0x10(%rbp)
0000000000000029 movq 0x70(%rip), %rdi ## Objc class ref: NSArray
0000000000000030 movq 0x91(%rip), %rsi ## Objc selector ref: arrayWithObjects:count:
0000000000000037 leaq -0x10(%rbp), %rdx
000000000000003b movl $0x2, %ecx
0000000000000040 callq *_objc_msgSend(%rip)
0000000000000046 addq $0x10, %rsp
000000000000004a popq %rbp
000000000000004b retq
libDeadpool.a(Deadpool.o):
(__TEXT,__text) section
-[Deadpool name]:
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 movq 0x1d(%rip), %rsi ## Objc selector ref: class
000000000000000b callq *_objc_msgSend(%rip)
0000000000000011 movq %rax, %rdi
0000000000000014 popq %rbp
0000000000000015 jmp _NSStringFromClass




хм, в самой либе все методы на месте, теперь посмотрим исходники приложения:



otool -tV -arch x86_64 DemoApp.app/DemoApp | grep Deadpool




выдает:



0000000100001ae8	movq	0x21f1(%rip), %rdi      ## Objc class ref: Deadpool
0000000100001af6 movq 0x1513(%rip), %r12 ## Objc message: +[Deadpool new]
-[Deadpool name]:




WTF! Окей гугл, где же все таки метод из категории?



гугл нам умело подсовывает ссылку на офф документацию эпла по этой как раз проблеме https://developer.apple.com/library/mac/qa/qa1490/_index.html, где беглый перевод говорит следующее:



The Linker



Когда си-программа скомпилирована, то каждый файл (.c) компилируется в так называемый «object file» (.o), который содержит реализацию функций и другую статичную информацию. После линкер собирает все эти файлы в один конечный файл — executable. И этот executable файл как раз и попадает внутрь нашей .app посредством Xcode.



Но когда source файл (.c) использует что либо, например функцию, что определено в другом файле (другой .c файл), тогда «undefined symbol» записывается в .o файл для этого участка кода. И на этапе сборки линкеру достаточно информации чтобы по «undefined symbol» понять откуда нужно вытащить недостающую вещь чтобы собрать конечный executable. Это описание для сборки UNIX static library.




Objective-C



Из-за динамической природы языка этот процесс в Objective-C немного усложенен, так как поиск реализации метода происходит только по факту обращения к этому методу. Objective-C не определяет вспомогательных symbols для методов линкеру, а только определяет symbols для классов. Например, в классе/файле main.o есть код:



[[FooClass alloc] initWithBar:nil]



то есть, FooClass это отдельный класс, в отдельном FooClass.o файле, так вот main.o будет только содержать «undefined symbol» для FooClass, но ни никаких дополнительных symbols для метода -initWithBar: в этом классе.



Так как категория это просто отдельный файл с методами, то у линкера нет совершенно никакой информации, что этот файл нужно слинковать, так как для методов не создаются вспомогательные линкеру «undefined symbol» штуки.




Так, вроде разобрались, еще раз посмотрим на байт код либы:



Archive : libDeadpool.a
libDeadpool.a(Deadpool+Guns.o):
(__TEXT,__text) section
-[Deadpool(Guns) guns]:
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 subq $0x10, %rsp
0000000000000008 leaq 0x71(%rip), %rax ## Objc cfstring ref: @"sword 2"
000000000000000f movd %rax, %xmm0
0000000000000014 leaq 0x45(%rip), %rax ## Objc cfstring ref: @"sword 1"
000000000000001b movd %rax, %xmm1
0000000000000020 punpcklqdq %xmm0, %xmm1 ## xmm1 = xmm1[0],xmm0[0]
0000000000000024 movdqa %xmm1, -0x10(%rbp)
0000000000000029 movq 0x70(%rip), %rdi ## Objc class ref: NSArray
0000000000000030 movq 0x91(%rip), %rsi ## Objc selector ref: arrayWithObjects:count:
0000000000000037 leaq -0x10(%rbp), %rdx
000000000000003b movl $0x2, %ecx
0000000000000040 callq *_objc_msgSend(%rip)
0000000000000046 addq $0x10, %rsp
000000000000004a popq %rbp
000000000000004b retq
libDeadpool.a(Deadpool.o):
(__TEXT,__text) section
-[Deadpool name]:
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 movq 0x1d(%rip), %rsi ## Objc selector ref: class
000000000000000b callq *_objc_msgSend(%rip)
0000000000000011 movq %rax, %rdi
0000000000000014 popq %rbp
0000000000000015 jmp _NSStringFromClass




Действительно, у нас скомпилировалось два файла Deadpool.o и Deadpool+Guns.o, так как второй файл это просто набор методов для первого, то линкер о нем ничего не знает и поэтому получаем эту ошибку только в рантайме.



Сразу первое решение — перенести категорию в файл основного класса. Да, это будет работать :) но для нас это не совсем удобно, так как мы привыкли все категории держать в отдельных папочках для порядка.



Другое решение. Тем, кто использует нашу либу, должны указать -ObjC флаг в «Other Linker Flags», этот флаг говорит линкеру загрузить всё всё всё из статичной либы. Ну, нам подходит это решение тем, что на нашей стороне ничего править не нужно. Но если подумать, если разработчик подключит кучу либ и только из-за нашей ему приходится добавлять этот флаг, то он может получить нехилое прибавление в весе для своего приложения (я так предполагаю).



А можно ли как то сказать линкеру, чтобы он собрал класс и его категории в один файл? Оказывается есть такое и название ему «Perform Single-Object Prelink» или «GENERATE_MASTER_OBJECT_FILE» в pbxproj файле. Правда происходит не просто объединение класса и его категории в единый файл, а все файлы проекта будут как единый «object file». Если это значение выставить в true, то мы должны получить поведение, которое хотим. Проверим.



Выставляем:







otool -tV -arch x86_64 libDeadpool.a




получаем:



Archive : libDeadpool.a
libDeadpool.a(libDeadpool.a-x86_64-master.o):
(__TEXT,__text) section
-[Deadpool(Guns) guns]:
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 subq $0x10, %rsp
0000000000000008 leaq 0x149(%rip), %rax ## Objc cfstring ref: @"sword 2"
000000000000000f movd %rax, %xmm0
0000000000000014 leaq 0x11d(%rip), %rax ## Objc cfstring ref: @"sword 1"
000000000000001b movd %rax, %xmm1
0000000000000020 punpcklqdq %xmm0, %xmm1 ## xmm1 = xmm1[0],xmm0[0]
0000000000000024 movdqa %xmm1, -0x10(%rbp)
0000000000000029 movq 0x270(%rip), %rdi ## Objc class ref: NSArray
0000000000000030 movq 0x259(%rip), %rsi ## Objc selector ref: arrayWithObjects:count:
0000000000000037 leaq -0x10(%rbp), %rdx
000000000000003b movl $0x2, %ecx
0000000000000040 callq *_objc_msgSend(%rip)
0000000000000046 addq $0x10, %rsp
000000000000004a popq %rbp
000000000000004b retq
-[Deadpool name]:
000000000000004c pushq %rbp
000000000000004d movq %rsp, %rbp
0000000000000050 movq 0x241(%rip), %rsi ## Objc selector ref: class
0000000000000057 callq *_objc_msgSend(%rip)
000000000000005d movq %rax, %rdi
0000000000000060 popq %rbp
0000000000000061 jmp _NSStringFromClass




Что и хотели, сейчас всё в одном файле. Убираем из приложения -ObjC и пересобираем с новой версией нашей библиотеки и смотрим:



otool -tV -arch x86_64 DemoApp.app/DemoApp | grep Deadpool




вывод:



0000000100001a70	movq	0x22c9(%rip), %rdi      ## Objc class ref: Deadpool
0000000100001a7e movq 0x158b(%rip), %r12 ## Objc message: +[Deadpool new]
-[Deadpool(Guns) guns]:
-[Deadpool name]:




Отлично. Сейчас можно обратно из readme.md удалять информацию о -ObjC флаге, смело открывать хабр и допивать, к сожалению, уже остывший кофе )



пс.



Проблема бородатая, давно ее решил, сейчас вот дошли руки написать и более подробно в этом разобраться )

Не уверен в идеальности решения, но мне помогло с этой проблемой, может кому будет интересно.



Полезные ссылки:



https://developer.apple.com/library/mac/qa/qa1490/_index.html

http://stackoverflow.com/questions/2567498/objective-c-categories-in-static-library



Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/283570/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество

Следующие 30  »

<вредные советы - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda