2016-12-29 2 views
2

Если у меня есть класс и инициализировать переменную так:Есть ли разница между глобальной инициализации против инициализации viewDidLoad в Swift

class TestClass: UIViewController { 
    var thisInt: Int = 10 
} 

это отличается чем инициализируется так:

class TestClass: UIViewController { 
    var thisInt: Int! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     thisInt = 10 
    } 
} 

Я полагаю, что мои основные вопросы заключаются в том, что когда происходит глобальная инициализация, и есть ли время, когда его можно было бы назвать более чем другим, вызывали бы с обычным программированием iOS (не делая ничего решительного против собственной разработки). Я понимаю, что делать это в viewDidLoad ограничивает меня использованием слабых или необязательных, но меня больше беспокоят любые другие различия.

ответ

3

Вы можете найти легко, добавив "вычисленный" свойство контроллера вида:

class TestClass: UIViewController { 
    let a = {()->Int in print("global initialization"); return 10 }() 
} 

и добавление

print("didFinishLaunching") 

в делегат didFinishLaunchingWithOptions метода приложения.

заказ вы получаете

global initialization 
didFinishLaunching 

что означает глобальные инициализаторы запускаются перед началом жизненного цикла приложения.

Теперь, чтобы пойти еще дальше, вы можете добавить main.swift файл со следующим содержимым

print("Before UIApplicationMain") 

UIApplicationMain(CommandLine.argc, unsafeBitCast(CommandLine.unsafeArgv, to: UnsafeMutablePointer<UnsafeMutablePointer<Int8>>.self), nil, NSStringFromClass(AppDelegate.self)) 

и удалить (или комментарий) в @UIApplicationMain украшение из вашего класса AppDelegate. Это даст указание компилятору использовать код в main.swift для инициализации приложения вместо стандартного поведения, предоставляемого декоратором в процессе обсуждения (хотя мы предоставляем практически идентичную реализацию).

Что вы получите в этом 2-го подхода является

Before UIApplicationMain 
global initialization 
didFinishLaunching 

, что означает, что код свойства экземпляра выполняется, когда раскадровка загружена.

Теперь, для более глубокого понимания, давайте попробуем выяснить различия между статическими переменными экземпляра. Для этого мы добавим тестовый класс:

class PropertyInitializationTest { 
    static let staticProp = {()->String in print("static initialization of InitializationTest"); return "" }() 
    let instanceProp = {()->String in print("instance initialization of InitializationTest"); return "" }() 

    init() { 
     print("In initializer") 
    } 
} 

и обновление AppDelegate в сделал закончить запуск:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 
     print("didFinishLaunching") 
     print("before instantiating InitializationTest") 
     _ = PropertyInitializationTest() 
     print("after instantiating InitializationTest") 
     // Override point for customization after application launch. 
     return true 
    } 

Выход мы получаем:

Before UIApplicationMain 
global initialization 
didFinishLaunching 
before instantiating InitializationTest 
instance initialization of InitializationTest 
In initializer 
after instantiating InitializationTest 

, что подтверждает тот факт, эти свойства экземпляра устанавливаются при создании экземпляра класса и перед запуском любого кода инициализации.

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

Обновление приложения завершило запуск кода, подтверждающего это.

print("didFinishLaunching") 
print("before instantiating InitializationTest") 
_ = PropertyInitializationTest() 
print("after instantiating InitializationTest") 
_ = PropertyInitializationTest.staticProp 
print("after instantiating InitializationTest") 

дает следующий результат:

Before UIApplicationMain 
global initialization 
didFinishLaunching 
before instantiating InitializationTest 
instance initialization of InitializationTest 
In initializer 
after instantiating InitializationTest 
static initialization of InitializationTest 
after instantiating InitializationTest 

Вывод:

  • свойства экземпляра получают значения времени компиляции (если он установлен) перед прогонов инициализаторе класса, таким образом, перед любым кодом из этого класса выполняется
  • Статические свойства получают свои значения только при первом доступе, они ленивы по своей природе
+0

Отличный ответ !!! Итак, это отвечает на мой вопрос. Другая половина. Было ли время, когда глобальная инициализация будет запущена без viewDidLoad или viewDidLoad без глобальной инициализации класса, в котором они находятся? Это предполагает, что он не падает в середине глобальной инициализации. – Sethmr

+0

@Sethmr Я обновил свой ответ с большим количеством результатов. Вывод состоит в том, что код 'viewDidLoad' будет всегда запускаться после глобальной инициализации, так как это часть настройки, выполняемой при создании экземпляра класса – Cristik

+0

. Спасибо за ваше время. Я могу копаться в таких вещах, но, услышав это от кого-то с более глубоким пониманием, он становится намного легче расти и видит лучший способ понять эти вещи в будущем. – Sethmr

1

Да, есть отличия. Хотя оба ваших примера технически работают, и ваш первый фрагмент является наиболее распространенным.

Я покажу вам один пример, когда вы на самом деле нужно реализовать его, как описано в вашем втором фрагменте:

class ImageDisplayingViewController: UIViewController { 
    @IBOutlet weak var thumbImageView: UIImageView! 

    var choosenImageTag: Int! 
    var choosenImage: UIImage! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     thumbImageView.tag = imageTag 
     thumbImageView.image = image 
    } 
} 

Допустим, у вас есть контроллер представления, где вы выбираете изображение, а затем перейдите к следующий контроллер представления для отображения этого изображения (и тега, чтобы сохранить Int как в вашем примере). Вы бы передать этот образ и тег в prepare(for segue:, sender:) по телефону:

destinationViewController.choosenImage = choosenImage 
destinationViewController.choosenImageTag = 10 

Тогда ImageDisplayingViewController будет фактически загрузить изображение в viewDidLoad() методе, когда вы уверены, что ваши выходы были инициализированы.

Если бы вы собрались попросить и загрузить изображение непосредственно в методе prepare(for segue:, sender:), вы получили бы сбой, так как выходы еще не были инициализированы.

destinationViewController.thumbImageView.image = choosenImage // crash 
destinationViewController.thumbImageView.tag = 10 
+0

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

+0

Я работаю в качестве разработчика iOS уже более года, и мне кажется, что я могу программировать практически все на этом этапе. Кажется, что все вопросы, которые у меня возникают для переполнения стека, совершенно разные и не отвечают, поскольку я хочу, чтобы они были. Виды вопросов, которые большинство людей просят, я чувствую, показывают отсутствие исследований на 95% + времени. – Sethmr

Смежные вопросы