Моя напыщенная речь о том, почему я ненавижу Objective-c.
Эта статья не является сравнением Swift и Objective-C. В эти дни я работал над проектом, написанным на obj-c, и он напомнил мне, как я полюбил писать код в быстром темпе, и некоторые причины, по которым я ненавидел obj-c.
Когда я начинал свою карьеру в разработке для iOS, Swift 2.0 только что вышел. Компания, в которой я работал, рано приняла его, и я получил возможность использовать Swift в первые дни его существования. Но, в отличие от сегодняшнего дня, почти все учебники по iOS, которые вы можете найти, были написаны на obj-c. Все проекты компании, многие сторонние библиотеки и фреймворки были в obj-c, поэтому у меня не было другого выбора, кроме как изучать obj-c вместе с Swift. Хотя в то время я ненавидел это, изучение обоих языков оказалось стоящим вложением.
Затем Swift стал популярным, и многие компании начали его внедрять. Новые приложения писались очень быстро. Учебники были перенесены на Swift. Одна из причин, почему я считаю, что Swift стал популярным, заключается в том, что его легче освоить для новичков. Я помню, как боролся с синтаксисом obj-c, когда начинал.
// swift let map = [String: Person]() // obj-c NSMutableDictionary<NSString *, Person *> *map = [NSMutableDictionary new];
Постепенно все больше и больше проектов, над которыми я работал, выполнялись в Swift, и я начал любить Swift больше, чем obj-c. Не поймите меня неправильно, obj-c - очень мощный язык, но в obj-c очень легко ошибиться, чем в swift.
Специальный переключатель:
Недавно я работал над проектом, написанным в объекте c, и он вернул мне воспоминания о том, почему я ненавидел obj-c. Поскольку в наши дни я пишу большую часть кода быстро, всякий раз, когда мне нужно писать код в obj-c, мой мозг должен постоянно переключать контекст между obj-c и swift. Много раз я обнаружил, что пытаюсь сделать что-то так, как я делаю быстро, например, вызов метода с использованием (точечной) нотации, с использованием String
вместо NSString
и т. Д.
// swift article.publish() // obj-c [article publish];
Другой пример странного синтаксиса - оператор switch в obj-c.
switch(value) { case @"A": NSLog(@"This is medium article"); break; case @"B": Article *mediumArticle = [[Article alloc] init]; break; }
Как только вы это напишете, компилятор начнет выдавать вам ошибку в случае B. Почему? Потому что, если вы хотите создать переменную в случае переключателя, ее нужно заключить в {}. Я совершил именно эту ошибку и потерял один час, пытаясь понять, почему корпус переключателя не работает. Потом почувствовал смущение, осознав свою ошибку.
switch(value) { case @"A": NSLog(@"This is case 1"); break; case @"B": { Article *mediumArticle = [[Article alloc] init]; break; } } // This works YAY!! 🎉
Также необходимо создать файл .h и .m для каждого класса, разные атрибуты для свойств, ivars, странную подпись метода, примитивные перечисления, отсутствие надлежащих модификаторов доступа, проблема с циклическим импортом - вот некоторые из вещей, которые мне не нравятся объективно -c.
Чтобы установить или не установить установить:
Как я сказал ранее, очень легко ошибиться в цели c. Позволь мне показать тебе.
Если вы объявите свойство с именем comment
и метод с именем setComment
, как показано ниже, это приведет к сбою вашего приложения при вызове этого метода.
@property (nonatomic) NSString *comment; - (void)setComment:(NSString *myComment) { self.comment = myComment; }
Почему? Узнай сам 🧐
Подсказка: это как-то связано с тем, как работает свойство в obj-c.
Любопытный случай с obj-c nil:
Иногда то, как работает obj-c, может вызвать странную ошибку в вашем коде. Позвольте мне рассказать вам об одной из моих недавних ошибок.
У меня было объявлено некоторое перечисление и свойство этого типа перечисления.
typedef NS_ENUM(NSInteger, Mood) { MoodHappy, MoodSad }; ... @property (nonatomic) EnumMood myMood;
Было установлено значение этого свойства: MoodSad
. Где-то в моем коде мне пришлось удерживать слабую ссылку self
. А затем получите доступ к этому перечислению, используя ссылку weakSelf
.
__weak typeof(self) weakSelf; switch (weakSelf.myMood) { case MoodHappy: NSLog(@"My mood is happy"); break; case MoodSad: NSLog(@"My mood is sad"); break; }
Ошибки, ошибки, везде 🐛 🐛
Несмотря на то, что значение свойства myMood
всегда было установлено равным MoodSad
, код никогда не достигал значения MoodSad
. Фактически, теперь, независимо от того, сколько случаев было для перечисления, код всегда выполнялся для первого случая в нашем перечислении, то есть MoodHappy
.
Прежде чем объяснять, какую ошибку я допустил, я хочу рассказать вам кое-что интересное о цели c. Для цели c вполне допустимо отправить сообщение на ноль. Т.е. даже если ваш объект равен нулю и вы выполняете его метод, вместо сбоя, он не действует во время выполнения.
// Object is nil Article *mediumArticle; // No Effect [mediumArticle publish];
Если этот метод возвращает объект, то возвращаемое значение - 0 (т.е. ноль). В моем случае я допустил опечатку. Мой weakSelf
был нулевым.
// Incorrect __weak typeof(self) weakSelf; // Correct __weak typeof(self) weakSelf = self;
Поэтому, когда я пытался получить доступ к значению перечисления myMood
, он всегда возвращал 0 (ноль). Но в области перечислений obj-c значение для первого случая перечисления равно 0, второго - 1 и так далее.
В результате мой оператор switch всегда выполнял оператор для enum case со значением 0, то есть MoodHappy
. Еще один час был потрачен на эту опечатку.
Objective-C - один из старейших и мощных языков, который до сих пор поддерживает некоторые фундаментальные фреймворки, которые мы используем при разработке iOS. Но все же я предпочитаю Swift Objective-C.
Надеюсь, вам понравилось читать.
Вы также можете прочитать эту статью прямо из моего блога по адресу https://nrlnishan.github.io/posts/objective-c-i-hate-you/