Pull to refresh
2
0
Федоров Руслан@aspcartman

User

Send message
Я согласен с тем, что описанный подход улучшает ситуацию. Но это не отвечает на вопрос, который я задал: зачем нужны сториборды вообще? Зачем нужно поддерживать какую-то дополнительную сущность, при работе с которой требуется быть очень осторожным, тратить так много времени на разброску констрейнтов и атрибутов контролов мышкой, заниматься копипастой, пробрасывать IBOutlet'ы и прочая прочая?
Уточню. Совсем. Никаких .storyboard, никаких .xib, никакого interface builder, никогда. Я не видел ни одного проекта за шесть лет опыта с IB, который был бы действительно хорошо написан. С .xib — да, было, но .storyboard — всегда ад. Даже если по сториборде на экран.

Давайте честно. Зачем нужны сториборды вообще? Вот альтернативный подход, критикуйте:
На каждый экран свой контроллер, и свой подкласс UIView. Весь лейаут и взаимодействие с пользователем — во вью, вся бизнесс логика — в контроллере. Контроллер пинает вью напрямую, вью — через протокол делегирования. Лейаут — через обертки аутолейаута по вкусу (KeepLayout), код в -updateContraints. Для ускорения процесса разработки — dyci или аналог (нажал хоткей — изменения в коде инжектировались и экран обновился).

Вот накипело уже. От IB одна только головная боль и толпы радостных индусов, размахивающих очередным новым способом не увязнуть в дебрях IB, продолжая использовать IB. Мыши плакали, кололись, но продолжали жрать кактус. Приходишь собеседоваться в большую серьезную компанию, а они пол года ваяют приложение и никуда оно не движется. Смотришь, код вроде бы нормальный, разработчики толковые и адекватные, а в сторибордах очередной срач, IBDesignable падает и не работает, все в каких-то страшных Segue и черт ногу сломает. Зато MVVC, IB, Swift, ага. Вам шашечки или ехать? Надоело переписывать за другими разрабами проекты. Нет, с одной стороны мне за это платят зарплаты, но с другой разобраться в этой дикой вермишели порой бывает без бутылки не возможно и нервы не резиновые.
А еще лучше просто не использовать сториборды вообще.
Real artists ship — настоящие художники доставляют.
Дословный перевод тоже не плохой, пусть и теряет смысл про сроки)
Так и не удается настроить по статье. Получаю neagent[58163]: Received error: Error (Authentication Failed) на OS X и iOS.

Не ясно, как сервер понимает, что пользователь «свой». Просто глядя на то, что его сертификат подписан тем же CA, чьи ключи указаны в ipsec.secrets?

Не ясно куда копать. Вроде бы все рекомендации и инструкции учел. Только вот dns имени нет, указывал везде и всюду вместо него IP адрес…
Кстати, волею судеб вынужден работать с C#. Вопрос к тем, кому скучно и он долистал до дна коментариев:
Как в С# симулировать поведение obj-c:
```
Class1 a = obj1.method1().method2()
```
В а должен оказаться null, даже если obj1 == null или obj1.method1() == null? Это какое-то издевательство бегать и ловить эти null'ы. Эквивалентный код:

```
Class1 a = null;
if (obj1 != null && obj1.method1() != null) { a = obj1.method1() }
```
Ну да, и мне интересен ответ на вопрос «а зачем так сделали?». Вон Swift сейчас с этими оптционалами городит. И зачем оно? А если меня устраивает null повсюду? А если в выражении `var firstCarIsRed = (containers.cars.firstObject.color == red)` меня не волнует, что containers == null / cars.count = 0? А если в 90% кода ситуация аналогичная? Моя мысль в том, что писать код гораздо проще несколько с другой стороны: проще требовать не-нулл в тех местах, где это важно, чем повсеместно проверять на null везде, чтобы оно не упало.
В Obj-C
```
(null).anyMethod == 0/null
```
и никаких nullReferenceException.

Это было чуть ли не идеальное решение.

> Обрабатывать это исключение бесполезно: оно означает безусловную ошибку в коде.

Что? Нет! Ну как, конечно если язык падает при доступе к такой переменной и заставляет ее всячески обворачивать то да, ошибка. А так — нет. И никаких лишних движений.
Больше всего понравился самый первый скриншот, прототип :)
Все хейтят IB потому что люди не умеют его готовить и строят громадные приложения в одной сториборде, а потом за ними переписывай.

И я заказчику накодю что угодно, и даже не буду ждать перекомпиляции проекта — хоткей и в симуляторе интерфейс перестроился. Если писать без обертки на чистом AL, то это действительно дольше, чем в IB.

AL без оберток очень плохо читаем.
iOS разработка != java dev != c++ dev. Тут другие правила и по факту 50 зависимостей в cocoapods гораздо лучше, чем свои решения и на практике проблем с ними не возникает. Есть непоправленная бага в стороннем проекте — форкни, поправь, в поде выставь ссылку на свой git, profit. Pull request не забыть сделать. Это гораздо быстрее, чем делать что либо самому. Потом на ваше место прийдет другой разработчик, и ему в этом всем разбираться.

А собственно ответьте на свой вопрос сами: а зачем? Чтобы понимать? Ясен перец нужно, а еще?

Добро пожаловать на борт.
Не используйте InterfaceBuilder. Он принесет больше боли, чем пользы. На всех платформах боль от использования средств создания интерфейса графическим путем примерно одинакова, но в случае ios/osx интерфейс эпически просто создавать из кода благодаря оберткам над AutoLayout (использовать его в чистом виде это как пить чистый спирт, не надо).

https://github.com/Tricertops/KeepLayout

Добавление Вашего таб бара бы выглядело в методе -loadView следующим образом:

```
MMTabBarView *tabBar = [MMTabBarView new];
tabBar.foo = bar; // тут выставляем всякие параметры
[view addSubview:tabBar];
tabBar.keepTopInset.equal = 0;
tabBar.keepHorizontalInsets.equal = 0;
tabBar.keepHeight.equal = 20; // Опционально, если автор не указал стандартный размер через -intrinsicContentSize
_tabBarIvar = tabBar;
```

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

И еще: AppCode, Cocoapods.

Happy coding! ^_^
Принято :) Не заметил.

Кстати, у Вас в структуре block ABI ошибка, на самом деле она выглядит вот так
struct ASPBlockDescriptor
{
__unused unsigned long int reserved;
__unused unsigned long int size;
union
{
struct
{
__unused void (*copy_helper)(void *dst, void *src);
__unused void (*dispose_helper)(void *src);
const char *copy_dispose_signature;
};

const char *usual_signature;
};
};

Документация is out of date, информацию о реальной имплементации можно найти в исходниках llvm. Разница не принципиальная, и так и так работает, но просто на заметку.

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

[object injectAfter:@selector(someMethod:) withBlock:^(id _s, ArgType arg){}];


Блок должен быть вызван в этом примере после отработки оригинальной имплементации и при этом с теми же аргументами. Решение готовое уже есть на гитхабе, можете поискать, но оно использует NSInvocation и, по сему, невероятно медленное (о чем говорит их дока и мой опыт). Однако инструмент очень полезен: можно, например, очень быстро распихать аналитику по всему приложению, не вставляя злосчастные вызовы логинга эвентов посреди бизнес логики или UI.

Нужно сделать без использования NSInvocation. Эта задача мне кажется интересней и сложнее. Все здорово, покуда можно использовать NSInvocation. А вот без него? :) (PS: как видно в примере, _s не убирается и не требуется: у Вас узкий кейс с лямбдами, а эта задача о другом и self часто нужен)
Сам имею аналогичное решение, похожее на анонимные классы в джаве:

tableView.datasource = [ASPDelegate delegate:^(ASPDynamicDelegate* delegate){

[delegate addSelector:@selector(tableView:numberOfRowsInSection:) withBlock:^NSUInteger(id _s, NSTableView *tv, NSUInteger section){
return 10;
}]

}];


И только для того, чтобы избавиться от id _s, вы решили прибегнуть к такому огромному количеству приседаний и использованию NSInvocation? Why?
О боже. Method swizzling это следствие всей прелести obj-c runtime и каждый разраб должен уметь готовить его с закрытыми глазами.
Оверрайд с помощью категорий это UB.

Т.е вместо того, чтобы поймать за шкирку контейнер вью и заменить класс в рантайме на нужный подкласс с таким пропускным поведением, Вы решили воспользоваться Undefined Behavior и поменять поведение hitTest во всех UIView.

О какой черной коробке вообще может идти речь, если она модифицирует метод во всей системе?

PS: Apple не банит и никогда не банила за использование функций obj-c runtime, откуда Вы это взяли.
Blocks ABI опушен, а это самый сок. Тема не раскрыта :) ведь блоки нужны для того, чтобы их вызывать, а как они вызываются вы не описали.

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

Пояснение:
Я не пользуюсь сторибордами, ксибами и строю весь интерфейс на аутолейауте с помощью KeepLayout. Сторонник мнения, что сториборды — зло. По этому вопросы могут показаться странными.

Вопросы:
1. Почему не реализовать нужные клетки в отдельных ксибах, по старинке, и просто зарегистрировать нужные классы так же, как вы делаете в статье? Кода, как либо связанного с IBOutletCollection не будет, и клетки могут быть использованы в разных контроллерах, без какой-либо привязки к сторибордам.

2. Что значит
И тут мы сталкиваемся с проблемой, что прототипы ячеек для таблицы придется класть во внешние Xib-ы, причем по одному в файл, и явно регистрировать их в коде. После использования Storyboard совсем не хочется так делать.
? Вы же именно это и делаете, регистрируете каждый по отдельности, только создаете ксибу для целого вью контроллера. А если клетки используются в разных контроллерах? Таким образом вы жестко привязали клетки к классу контроллера, но с теоретической стороны связи быть не должно и потребуются дополнительные телодвижения для того, чтобы позже это исправить, плюс вы уже совершили больше телодвижений, чем можно было для достижение цели строить интерфейс графически.

3. Что значит
Теперь таблица может работать, как будто ее загрузили из Storyboard.
? В чем отличие поведения UITableView, созданной в сториборде, от онной, созданной в коде?

4.
- (NSArray*)cellPrototypes { return nil; } //Чтобы не было warning-a
Серьезно? Вы только что все сломали. Обьясните, пожалуйста, читателям, почему класс, которому добавили аксессорный метод, возвращающий nil, когда либо будет возвращать по этому проперти не nil? Расскажите, как работает Extensions в Obj-C? Метод, который я имплементировал в Extension, когда и как добавляется в класс? Расскажите, как работает IBOutlet/IBOutletCollection для property? При загрузке из nib выполняется -setPropertyName: или же в рантайме имплементируется геттер -propertyName? Если первое, то почему нет краша, ведь поведение проперти по умолчанию это
@sythnesize propertyName = _propertyName;
, а ClassExtensions не умеет добавлять iVar'ы в класс по очевидным причинам, и для Extensions пропертя делается (скорее всего, я не компилировал такой случай на моей практике без имплементации аксессорных методов в extension, чтобы посмотреть, что будет)
@dynamic propertyName

и ожидает, что вы имплементируете свои методы, и если вы этого не сделаете, то будет краш. Если же второе, то почему ваша имплементация, если код рабочий, оверрайдится имплементацией для IBOutlet? Это противоречит ожидаемому поведению dynamic пропертей в Foundation и ко. Например NSManagedObject в CoreData. Да и о каком конкретно ворнинге речь, и почему вы просто от него отмахиваетесь?

Предложения:
5. Все связанное с высотой клеток, имхо, стоит вынести в классы самих клеток, а точнее имплементировать их суперкласс, который будет хранить «невидимые» клетки по именам классов и блоки их инициализаций, заместо нагружения лишним кодом ваш контроллер.

6.
static char cellPrototypesKey;
// ...
objc_setAssociatedObject(self, &cellPrototypesKey, cellPrototypes, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
Вы только что создали бестолковую переменную, которая торчит в скопе всего файла. Вместо этого предлагается (http://nshipster.com/associated-objects/) делать
objc_setAssociatedObject(self, @selector(getterName), cellPrototypes, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
Ключи бы я изначально выставил. А затем предложил бы для товарищей код-ревью бекграунд аудио какое-то, мол, смотрите, вот по делу. А на самом деле с дарк релизом бы эту обманку выключил.
Для того, чтобы так сильно заморачиваться, должны быть веские причины. Мой посыл лишь в том, что это возможно.
Может, наоборот, учитывая время выхода статей? :)
posix_spawn режется. Имхо режутся все системные вызовы по номерам. Еще варианты?

Да ладно, не жалуют, самые одаренные малвар-кодеры потом и пишут весь фундамент, на котором все работает. Ну, если в плохих мальчиков надоест играть. :3
Пропускает или нет не важно
а) Enterprise Program не имеет стадии ревью
б) Все, что не пропускает ревью, можно зарелизить с помощью Dark Release.

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity