Swift: зачем мне вообще нужны опции?

Я прочитал несколько статей об этом, понял основной принцип и согласен с тем, что в некоторых случаях это может быть полезно. Однако в большинстве случаев я хотел бы, чтобы моя программа падала, если бы я получал nil где-то, чего не должен был - вот как я узнал, что есть проблема!

Кроме того, я читал, что использование опций может привести к сокращению кода. Как это возможно?? Из того, что я видел, вся идея, стоящая за ними, заключается в том, что они могут иметь либо значение, либо nil, поэтому вам нужно выполнить дополнительную проверку, тогда как раньше в этом не было необходимости!

А что не так с необходимостью использовать «как» все время? Это просто делает все более многословным и длинным. Например, сравните следующий код в Objective-C и Swift.

Цель-С:

UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"Home"];
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
appDelegate.window.rootViewController = vc;
[UIView transitionWithView:appDelegate.window
                          duration:0.2
                          options:UIViewAnimationOptionTransitionCrossDissolve
                          animations:^{ appDelegate.window.rootViewController = vc; }
                          completion:nil];

Быстрый:

//have to check if self.storyboard != nil
let viewController:UIViewController = self.storyboard?.instantiateViewControllerWithIdentifier("Home") as UIViewController; //Isn't the view controller returned by instantiateViewControllerWithIdentifier() already of type UIViewController?
let appDelegate:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate; //Isn't the delegate returned by sharedApplication() already of type AppDelegate?
//have to check if appDelegate.window != nil
appDelegate.window!.rootViewController = viewController as UIViewController; //Why cast viewController as UIViewController if the type has already been explicitly set above?

UIView.transitionWithView(
    appDelegate.window!,
    duration: 0.2,
    options: UIViewAnimationOptions.TransitionCrossDissolve,
    animations:{appDelegate.window!.rootViewController = viewController as UIViewController},
    completion: nil
);

Я делаю что-то неправильно? Или это действительно так, как было задумано?


person null pointer exception    schedule 15.03.2015    source источник
comment
as в конце заменяет тип в начале в Objective-C, так что это в значительной степени размытие в отношении многословия. Вам также не нужны оба :ClassName и как ClassName - вам не нужно :ClassName перед =. У вас также не должно быть точки с запятой в конце строки в Swift.   -  person rdelmar    schedule 15.03.2015
comment
Проверьте документы для возвращаемых типов. Нет, возвращаемый тип для instanceiateViewControllerWithIdentifier — это не UIViewController, а идентификатор. Вот почему вам нужен as   -  person rdelmar    schedule 15.03.2015
comment
Возможно, потому, что Свифт тупой. Это не будет автоматически принуждать. Вы должны явно бросить одно в другое. Упс, где твой комментарий?   -  person qwerty_so    schedule 15.03.2015
comment
А, это объясняет это. Спасибо. Я до сих пор не понимаю, зачем использовать опции. Конечно, вы хотите поймать, когда что-то nil, но за счет необходимости всегда проверять nil? Мне кажется намного больше кода   -  person null pointer exception    schedule 15.03.2015
comment
Что бы это ни стоило, код Objective-C был бы таким же подробным, если не более, если бы вы действительно включали проверки, чтобы убедиться, что ваши переменные имеют типы, которые вы предполагаете, и respondsToSelector: проверяет вызовы методов и свойства доступ.   -  person Mick MacCallum    schedule 15.03.2015
comment
Я также не очень убежден в необязательной концепции. Но это дискуссия, основанная на мнениях, которая не приветствуется здесь, на SO.   -  person qwerty_so    schedule 15.03.2015


Ответы (1)


Необязательно

Если вы точно знаете, что переменная никогда не должна быть равна нулю, вы можете принудительно развернуть опциональную переменную с помощью ! или объявить ее неявно развернутой с помощью String!. Это приведет к сбою, когда оно равно нулю, как вы и хотите.

Но с некоторыми переменными разумно, чтобы они были нулевыми. Например, модель User, переменная age которой не задана, поскольку пользователь не предоставил ее.

Явно помечая их как необязательные и разворачивая их с помощью if let, вы заставляете задуматься о допустимости значений NULL. В конце концов, это создает более надежный код.

Я не думаю, что это приводит к короткому коду. Там, где в Objective-C вы использовали бы if var != nil, вы используете if let var = var в Swift. Отправка сообщения на nil в Obj-C — это noop, вы можете получить такое же поведение в Swift, используя var?.method(). В итоге тоже самое.

Трансляция (как)

Основная причина, по которой вам нужны приведения прямо сейчас в Swift, заключается в том, что некоторые методы Objective-C возвращают id, что не было проблемой в Obj-C, но вызывает проблемы в Swift. Я ожидаю, что это уменьшится по мере того, как Swift станет более популярным, а фреймворки будут адаптированы.

Обновленный код

Я быстро просмотрел ваш код, и похоже, что вам не нужна половина этих приведений. Это из головы:

if let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("Home") as? UIViewController {
    if let window = UIApplication.sharedApplication().delegate?.window {
        window.rootViewController = viewController

        UIView.transitionWithView(window, duration: 0.2, options: .TransitionCrossDissolve, animations: {
            window.rootViewController = viewController
        }, completion: nil);
    }
}
person Rengers    schedule 15.03.2015
comment
Ах, спасибо, прекрасное объяснение того, почему это необходимо. Что касается опций, похоже, что в целом лучше просто быть немного более подробным и использовать if let var = var, а не просто принудительно разворачивать? Меня просто убивает необходимость добавлять все эти проверки, когда, например, self.storyboard никогда не должно быть nil в любом случае. Но если бы это было так, разве вы не хотели бы, чтобы ваша программа рухнула, чтобы вы точно знали, в чем проблема? Кажется, это почти усложняет отладку. - person null pointer exception; 15.03.2015
comment
Итак, я просто вставил ваш код в Xcode, и window.rootViewController = viewController выдает ошибку «UIWindow?» не имеет члена с именем «rootViewController» - person null pointer exception; 15.03.2015
comment
Это зависит от ситуации. Для раскадровки я принудительно разворачиваю, потому что я знаю, что это не ноль. И даже если бы он был равен нулю, мое приложение не смогло бы продолжить работу, поэтому я не против сбоя в этот момент. - person Rengers; 15.03.2015
comment
Приятно знать, что это больше соответствует тому, как я ожидаю, что это будет выглядеть. Что касается вышеуказанной ошибки, я просто принудительно разворачиваю окно if let window = UIApplication.sharedApplication().delegate?.window! - person null pointer exception; 15.03.2015
comment
Похоже, это объясняется здесь: stackoverflow.com/questions/28901893/ - person Rengers; 15.03.2015