Pull to refresh

Comments 16

Автор спасибо! Статья очень полезна, и не только новичкам. Спасибо огромное! Но, ёпрст, Objective-C, а не ObjC. У меня как у профессионального программиста на этом языке и препода на ту же тему, кровоточат глаза, когда я читаю такие наименования.
Боюсь что языки и технологии с названиями длиннее пары слогов просто обречены на сокращение: javascript -> js, ruby on rails -> rails, visual basic .net -> vb.net, assembly -> asm, gnu emacs lisp -> elisp и т. д.
Что поделать с перфекционизмом? :-)
Автор, спасибо! Использую каждый день ;)
Огромное спасибо за статью! Объемлющая и глубокая.
Если я правильно понял, то этот подход употребим для практически каждого блока в коде, соответственно возникает вопрос:
В качестве вариантов, которые приходят в голову
-Добавление скрипта во время процессинга .m файлов, который будет по маркеру или просто так обнаруживать блоки и преобразовывать их в нужный вид — тогда можно будет обойтись одним макросом, без замыкающего weakself_end.
-Добавление сниппета/скрипта автоматора c примерно похожим поведением, но явного — который выделенный блок приведет к нужной вам форме?
В общем случае не в каждом блоке нужно захватывать self по слабой ссылке, иногда нужно наоборот по сильной. И не все блоки создаются в контексте метода, поэтому self не всегда существует. К тому же @weaksekf блок будет обязательно перенесен в heap, а это лишний overhead когда подходит и стековый (например enumerateObjectsUsingBlock:). Поэтому все блоки заворачивать в этот макрос я не рекомендую. Если добавить файлы автокомплита в Xcode, то после набранных символов @we дополняется заглушка сразу с @weakselfend. Я не сторонник дополнительного препроцессинга перед сборкой, а в коде существующие блоки меняли на новые простым макросом в vim.
Я очень люблю простые решения понятные большинству программистов разного уровня и потому для себя решаю эту проблему следующим образом:

__weak MyClass *weakSelf = self;
self.block = ^{
	[weakSelf onlyOneMethodCall];
};

- (void)onlyOneMethodCall
{
	[self m1];
	[self m2];
	NSAssert(foo == bar, @"Cool assert!");
}


Дело в том, что ARC гарантирует, что self будет жить пока не завершится вызов метода, потому вызываем 1 метод из блока и все остальное внутри этого метода. Если надо использовать переменные окружения — я их передаю в метод как параметры.
Так это тоже самое, что и старые добрые делегаты, или даже скорее target-selector, только с ненужной прослойкой из блока.
Делегирование это паттерн передачи полномочий и никак не зависит от метода его реализации тоже касается и концепта target-selector. Данный кусок кода как раз таки решает исключительно проблему циклических ссылок. Я не говорю, что 2 + 2 надо выносить в отдельный метод, но если и так наглядно, что код внутри блока сложен — почему бы не вынести код в отдельный метод? Каждая дополнительная инструкция введенная в ваш проект (вроде @weakify) усложнит задачу входа следующих сотрудников.
В случае с weakSelf, если в блоке более двух его использований, придется выносить отдельный метод, а это большая часть блоков. Конечно использование чего-то, за рамками базового языка и API усложняет задачу входа новых сотрудников, зато сильно упрощает жизнь текущим сотрудникам. Тут баланс надо подбирать в зависимости от ситуации.
>Дело в том, что ARC гарантирует, что self будет жить пока не завершится вызов метода
Это неправда.
На блоки опираться в том случае лучше, объект если знает о времени своей кончины или одноразовым является. Смело он может лямбдические свойства обнулить перед смертью своей, циклы разорвав нерушимые. В том случае же, когда жизни окончание объекта неведомо самим объектом, то коллбека выполнение в виде делегата лучше будет. Ссылку он имеет слабую, и тем самым цикл создать не может.

Ваш очевидности магистр.

(за решение спасибо, не додумался бы в макрос обернуть)
с RAC все сложнее получается. Да и не все API предоставляют альтернативу в виде делегатов.
Sign up to leave a comment.