Как стать автором
Обновить

Комментарии 41

Маленькое замечение

MyViewController* controller = [MyViewController initWithNibName:NSStringFromClass([MyViewController class] bundle:nil];


в 99% случаев будет аналогично:

MyViewController* controller = [MyViewController initWithNibName:nil bundle:nil];


И даже так:

MyViewController* controller = [MyViewController new];
Да, там в реализации по умолчанию
NSStringFromClass([self class])
это только примеры, для иллюстрации основной идеи
Для iOS — да, но на OS X нужно указывать валидное имя.
Познавательно, но непрактично.

С теми же ксибами, в большинстве проектов приходится делать так
if (iPad) {
    [KingViewController initWithNibName:@"KingViewController"];
} else {
    if (iPhone5) {
        [KingViewController initWithNibName:@"KingViewController-568h"];
    } else {
        [KingViewController initWithNibName:@"KingViewController-480h"];
    }
}



Как тут упростить диагностику до стадии компиляции без лишних усилий?
Попробуйте называть ксибы KingViewController и KingViewController~ipad.xib — это избавит вас от одного сравнения в рантайме. А для решения проблемы 568/480 пикселей в высоту — используйте AutoresizingMask / Autolayout. Это избавит вас от необходимости поддерживать 2 интерфейса вместо одного для iPhone
НЛО прилетело и опубликовало эту надпись здесь
Если интерфейс так разительно отличается из-за половины дюйма, да так, что AutoresizingMask / Autolayout не спасают, то стОит подумать. Стоит сильно подумать что не так с интерфейсом. Или почитать про AutoresizingMask / Autolayout подробнее. Или вычислить положение некоторых элементов в рантайме. И только в крайнем случае заводить два ксиба для одного и того-же экрана под 3.5 / 4 дюйма. Так как поддержка двух вьюх для одного и того-же контроллера — занятие утомительное и неблагодарное. ИМХО опять-же
НЛО прилетело и опубликовало эту надпись здесь
Так серебряной пули не существует. Нужно, конечно, всегда смотреть от контента. Но, согласитесь, что такой UI — это не норма, а скорее наоборот. И для одного окна можно и 2 ксиба завести. Но в подавляющем большинстве случаев UI отлично растягивается/перемещается автоматически.
Смысл статьи немного не о именовании ксибов для исключительных случаев — а в том, чтобы помочь компилятору выявлять как можно больше ошибок еще до того, как приложение запустится и упадет
Дать дизайнеру по почкам?
Ксиб не обязан иметь имя класса. Один ксиб может содержать внутри много разных шаблонов, например все виды ячеек таблиц, используемых в приложении. Эдакая фабрика объектов, чей дизайн создавался в IB. Иными словами, ксиб может быть вьюхой, возможно в большинстве приложений это так и есть, но он вовсе не обязан нею быть.
Не обязан, но желательно, чтобы один ксиб содержал один объект(вьюху, ячейку, контроллер).
Если ксиб содерджит 20 вьюх/селл, а нам нужна всего одна, то в память будут загружены и инстанциированы все 20 вьюх.
Если же одна вьюшка содержит аутлеты на остальные, то не проблема назвать сам ксиб но имени класса этой вьюшки.
Если нам нужна одна, остальные исчезнут после загрузки, ибо потеряют ссылки, только Dirty память пофрагментировав слегка. Связывать их между собой обычно смысла нет(тем более ячейки таблиц вообще мало с чем можно эффективно связать в IB, внешним по отношению к самой ячейке).
Зная эти особенности, можно вполне организовать кеш ячеек, запасая загруженные «вхолостую» впрок.
А так-то многие в ксибах хранят вьюху, внутри нее View Based NSTableView, внутри которой руками рисуют кастомную NSTableCellView, автосоздание которой отдают на откуп самому NSTableView, после чего даже не задумываются, что каждый раз, когда табличка создает очередную ячейку, инстанцируется не только ячейка, а весь ксиб.
Ну это все лирика. По теме — я согласен с PapaBubaDiop: это непрактично(впрочем, строки тоже не красиво, в этом я согласен с вами).
Если уж и надо, чтоб компилятор ругался, так константы объявить можно где-нибудь с нормальными названиями — и компилятор ругаться будет, и автокомплит подсказывать и дополнять, и если уж совсем туго с ориентированием в этом хозяйстве — для страховки тестами покрыть можно.
Боже упаси меня от авто выравниваний. Все мои кнопки, заданные в ксибах, прыгают смеются дышат. Включение выравнивания их убивает, они не могут двигаться. Для неигровых приложений Ваше предложение разумно.
Игровые приложения на UIKit? Окей.
На самом деле для большинства казуальных 2-d игр UIKit для меню и всего неигрового — отличный выбор. Для экрана самой игры — тот-же CCViewController (если вы используете cocos2d). Можно хоть xib-ы, хоть storyboard-ы использовать. (у меня так пару игровых приложений написана)
Другое дело, что даже красивая анимация, смех и дышание кнопок никак не противоречат авторесайзу
Ну я сейчас подумал что прекрасный Letterpress вроде бы на UIKit тоже, да.
Вот, кстати, замечательная статья о разработке cocos2d игры с использованием Storyboard
Научите как двигать программно кнопки, заданные через ксибы с авто выравниванием, интересно.
Если под авто выравниванием понимаете autoresizing mask, то все банально до неприличия:
someButton.center = newCenterCGPoint;

Ну и анимировано:
[UIView animateWithDuration:0.3f animations:^{
     someButton.center = newCenterCGPoint
 }];

Если же под авто выравниванием вы понимаете Autolayout, то, к сожалению я не так плотно с ним работал. Но вот, нарыл гуглением:
— изменяются константы autolayout'а, после чего делается
[self.view layoutIfNeeded];
Хорошая статья, от string typing надо избавляться любой ценой
Мне кажется, что string typing — надуманная проблема. Objective-C — это динамический язык и превращать его в статический С++ — это неверный путь. Как по мне, нужно следовать «родным» шаблонам разработки. А от опечаток и прочих недостатков строк можно избавиться с помощью юнит-тестирования.
Юнит-тестирование долно тестировать логику, а не опечатки.
чаще всего при опечатках логика и не будет работать.
Вы проверяете в unit-тестах что увас верно заргузился контроллер с ксибом?
а вы пишете приложение и ни разу не запускаете хотя-бы в эмуляторе? Я думаю на этом этапе как раз опечатки в названиях ксибов и пропадут.
Вы часто делаете рефакторинг? Вы часто изменяете reuseIdentifiers / storyboardID? Вы переименовуете имена пропертей? Вы плотно работаете с CoreData? Никто не спорит: Objective-C динамичен и прекрасен в своей гибкости. Но некоторые вещи я лучше доверю компилятору. Именно поэтому я не отключаю Static Analyser. Именно поэтому я буду использовать инструменты, позволяющие выявлять ошибки на стадии компиляции.
Я ценю свое время.
Рефакторинг делаю крайне редко при крайней необходимости. Если честно, в масштабах iOS приложений рефакторинг провожу только в чужом коде, в своем ни разу не было такого.

Вы плотно работаете с CoreData?

Плотнее некуда.

Именно поэтому я буду использовать инструменты, позволяющие выявлять ошибки на стадии компиляции.

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

Я ценю свое время.

А нужно еще думать о времени других разработчиков, в том числе тех, которые потом будут разбираться в ваших «нестандартных» подходах.

Вы часто изменяете reuseIdentifiers / storyboardID? Вы переименовуете имена пропертей? Вы плотно работаете с CoreData?

Это надуманные проблемы, ошибки в этих примерах приводят к падению приложения при первом же обращения к «неизмененным» данным. Плюс инструменты рефакторинга переименовывают и iVar'ы (если их еще кто-то использует) и названия свойств и все места где они используются (так для примера о надуманности приведенных аргументов).
Я что-то не совсем понимаю. Вы работаете с CoreData, но будете продолжать писать FetchRequest-ы оперируя строковыми константами, вместо того, чтобы использовать библиотеки, которые на порядки уменьшат количество кода (и соответственно ошибок), таких как ActiveRecord for Core Data. Вы предпочитаете не использовать инструменты автоматизирующие рутинные операции, а писать все руками? По поводу свойств — я говорил о KVO и KVC: рефакторинг в Xcode не настолько умен, чтобы переименовать и строковые константы вместе со свойствами.
Наверное я вас неправильно понял.
Все вышеописанное совсем не надуманные для меня проблемы. Это проблемы, с которыми я встречаюсь каждый день. И в своем, и в чужом коде. Я лишь описал один из способов решения этих (с моей точки зрения) проблем.
Эти библиотеки и утилиты сэкономили мне кучу времени и нервов. И я буду рад если помогут и другим.
Если для вас эти подходы сложны, неочевидны и нестандарты — не используйте их.
естественно, что нужно использовать и фреймворки и инструменты для облегчения труда.
Но я лишь говорил, что те проблемы, о которых вы писали в статье — надуманные. Естественно и ваше и мое мнения — субьективны и каждый для себя сам выбирает путь. Для того комментарии и нужны, чтоб высказать альтернативную точку зрения, что я и сделал. И привел собственно аргументы.

Вы работаете с CoreData, но будете продолжать писать FetchRequest-ы оперируя строковыми константами, вместо того, чтобы использовать библиотеки, которые на порядки уменьшат количество кода (и соответственно ошибок), таких как ActiveRecord for Core Data


Библиотеки как правило увеличивают количество кода (я понимаю что вы имели ввиду, но просто озвучил другую сторону медали), и еще могут снизить производительность и увеличить количество ошибок. Любую библиотеку перед использованием нужно хорошо изучить, а не полагаться на чужую внимательность и компетентность.
Как правило в 60 процентах я борюсь в ошибках и тормозах чужого кода, а не собственного, именно поэтому так и говорю.

Рефакторинг в XCode работает не очень хорошо, но в AppCode все намного лучше.

Я лишь пытаюсь сказать, что во всем должна быть мера и переносить шаблоны и подходы с других языков нужно осторожно и вдумчиво.
AppCode умен, да. Но все равно, замена строкового литерала свойства ВЕЗДЕ где нужно — непростая задача.

Если вы 60% времени боритесь с ошибками в зависимостях — значит что-то с процессом выбора библиотек не так.

А по поводу переноса шаблонов из других языков — нельзя их бездумно переносить, если они лишают Вас каких-то возможностей динамичного рантайма ObjC. Что Вы теряете в описанных в статье случаях? Вместо @«someProperty» будет @keypath(object.someProperty)? Серьезно? Да в этом любой джуниор за полчаса разберется.
Если вы 60% времени боритесь с ошибками в зависимостях — значит что-то с процессом выбора библиотек не так.

Вы опять переиначиваете. Я не 60 процентов времени борюсь с ошибками в зависимостях, а 60 процентов времени оптимизации провожу оптимизацию чужого кода а не собственного.
Ну пока идеального ничего не встречал, те-же MagicalRecord и mogenerator входили в число этого кода.

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

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

Что Вы теряете в описанных в статье случаях? Вместо @«someProperty» будет @keypath(object.someProperty)? Серьезно? Да в этом любой джуниор за полчаса разберется.

Я не говорю о сложностях, я говорю о чюжеродности. Хранить указатели на Objective-C функции тоже можно, и разобраться в этом может любой джуниор, как вы выразились. Вопрос просто зачем, если есть блоки. А даже когда их небыло, то колл-бэки лучше было бы делать родными механизмами (центр уведомлений или шаблон делегирования например). Понятно что указатели бы работали быстрее и понятнее для любого С/С++ разработчика, но вопрос, зачем это делать, ради чего?

Вот так и в вашем случае, я лично не вижу вообще никаких оснований и доказательств того, что эта статическая проверка экономит время.
т.н. Global blocks кстати как раз и являются обычными указателями на функцию. Это когда блок ничего из внешнего контекста не использует и аллоцируется статически при компиляции. Это я к тому что пример очень неудачный, где-то блоки могут работать также, как указатели на функцию. Там где нужно замыкание — в C++ тоже не обойдешься простым указателем.

Если Вы действительно не видите преимуществ статических проверок — думаю нет смысла дальше что-то обсуждать.
И кстати даже сейчас некоторые вещи лучше делать делегатами, а не использовать везде блоки «потому что можем»
Ну видимо у человека бэкграунд из динамических языков, отсюда пренебрежение потенциальными compile-time проверками :(
неверные домыслы, мой бэкграунд: C/C++, и пренебрежения нет. О причинах я писал выше.
Я не утверждал обратного. Вы написали что эти ошибки можно выявить при помощи юнит-тестов.
про ксибы я не говорил ничего.
Большое спасибо!
Это лучшее что я прочитал на хабре за месяц!
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории