如果我有一个类并初始化一个这样的变量:
class TestClass: UIViewController {
var thisInt: Int = 10
}
与初始化不同:
class TestClass: UIViewController {
var thisInt: Int!
override func viewDidLoad() {
super.viewDidLoad()
thisInt = 10
}
}
我想我的主要问题在于全局初始化发生的时间,并且有时候一个人被调用的次数超过另一次调用普通的iOS编程(没有对本地开发做任何大的事情)。我明白在viewDidLoad中这样做会限制我使用弱或可选,但我更关心其他任何差异。
答案 0 :(得分:3)
您可以通过添加"计算"轻松找到答案。视图控制器的属性:
class TestClass: UIViewController {
let a = {()->Int in print("global initialization"); return 10 }()
}
并添加
print("didFinishLaunching")
在app的委托didFinishLaunchingWithOptions
方法中。
您获得的订单是
global initialization
didFinishLaunching
这意味着全局初始化程序在应用程序生命周期开始之前运行。
现在,为了更进一步,您可以添加一个包含以下内容的main.swift
文件
print("Before UIApplicationMain")
UIApplicationMain(CommandLine.argc, unsafeBitCast(CommandLine.unsafeArgv, to: UnsafeMutablePointer<UnsafeMutablePointer<Int8>>.self), nil, NSStringFromClass(AppDelegate.self))
并从AppDelegate类中删除(或评论)@UIApplicationMain
装饰。这将指示编译器使用main.swift
中的代码进行应用程序初始化,而不是讨论中装饰器提供的默认行为(尽管我们提供了一个自定义的几乎相同的实现)。
你在第二种方法中得到的是
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
总结:
答案 1 :(得分: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