我遇到了非常奇怪的情况,使用一个带有惰性关键字的属性.我知道这个关键字表示一个属性的初始化是直到该变量实际使用并运行一次.

但是,我发现一个案例运行初始化两次.

class TestLazyViewController: UIViewController {

    var name: String = "" {
        didSet {
            NSLog("name self = \(self)")
            testLabel.text = name
        }
    }

    lazy var testLabel: UILabel = {
        NSLog("testLabel self = \(self)")
        let label = UILabel()
        label.text = "hello"
        self.view.addSubview(label)
        return label
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        testLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
        NSLayoutConstraint.activateConstraints([NSLayoutConstraint(item: testLabel,attribute: .CenterX,relatedBy: .Equal,toItem: self.view,multiplier: 1.0,constant: 0.0)])
        NSLayoutConstraint.activateConstraints([NSLayoutConstraint(item: testLabel,attribute: .CenterY,constant: 0.0)])
    }

    @IBAction func testButton(sender: AnyObject) {
        testLabel.text = "world"
    }
}

我写了一个视图控制器进行测试.该视图控制器由另一个视图控制器呈现.然后,在显示视图控制器的prepareForSegue中设置name属性.

override func prepareForSegue(segue: UIStoryboardSegue,sender: AnyObject?) {
    let vc = segue.destinationViewController as! TestLazyViewController
    println("vc = \(vc)")
    vc.name = "hello"
}

运行测试后,我得到以下结果.

vc = <testLazy.TestLazyViewController: 0x7fb3d1d16ec0>
2015-05-25 00:26:15.673 testLazy[95577:22267122] name self = <testLazy.TestLazyViewController: 0x7fb3d1d16ec0>
2015-05-25 00:26:15.673 testLazy[95577:22267122] testLabel self = <testLazy.TestLazyViewController: 0x7fb3d1d16ec0>
2015-05-25 00:26:15.674 testLazy[95577:22267122] testLabel self = <testLazy.TestLazyViewController: 0x7fb3d1d16ec0>

您可以看到,初始化代码执行两次.我不知道这是一个错误或滥用.有没有人让我知道什么是错的?

我也猜测,在初始化代码中将testLabel添加到self.view中是不正确的.我不知道代码是不正确的.这只是我的猜测.

更新:
我还是不明白为什么懒惰初始化运行两次.这是Swift的错误吗?

最新更新:
@matt已经很好地解释了这个问题被初始化了两次.虽然所有的东西都来自我错误的代码,我可以获得关于懒惰关键字如何工作的宝贵知识.谢谢亚马逊

解决方法

你的代码的整个概念是错误的.

>在prepareForSegue中,由于没有接口,所以不能引用目标视图控制器的接口. viewDidLoad尚未运行;视图控制器没有视图,没有插座,没有任何东西.
>您的标签属性的延迟初始化程序也不应该将标签添加到接口.它应该只是使标签和返回.

其他事情要知道:

>参考视图控制器的视图,它有一个视图将强制该视图加载过早.这样做可能会导致视图加载两次,这可能会产生可怕的后果.
>查看控制器的视图是否已加载,而不强制视图过早加载的唯一方法是使用isViewLoaded().

您想要做的正确程序是:

>在prepareForSegue中,将名称字符串分配给name属性,这就是所有.它可以有一个观察者,但是如果我们当时没有任何视图,那么观察者不能引用视图,因为这样做会导致视图过早加载.
>在viewDidLoad中,然后只有我们有一个视图,现在你可以开始填充界面. viewDidLoad应该创建标签,将其放入界面,然后选择name属性,并将其分配给标签.

编辑:

现在,已经说了这一切…它与你的原始问题有什么关系?你在做什么错误在这里解释Swift正在做什么,Swift正在做错什么?

要看到答案,只需放一个断点:

lazy var testLabel: UILabel = {
    NSLog("testLabel self = \(self)") // breakpoint here
    // ...

您将看到的是,由于您构建代码的方式,我们以递归方式获取testLabel的值.这是调用堆栈,略简化:

prepareForSegue
name.didset
testLabel.getter -> *
viewDidLoad
testLabel.getter -> *

testLabel getter是指视图控制器的视图,它导致视图控制器的视图被加载,因此它的viewDidLoad被调用,并导致再次调用testLabel getter.

请注意,吸气剂不仅仅是按顺序调用两次.它被递归调用两次:它本身实际上称之为自己.

这是递归的,斯威夫特是不能防御的.如果连接器只是连续两次被调用,那么这个懒惰的初始化器就不会被第二次调用了.但在你的情况下,它是递归的.所以这是真的,第二次,这个懒惰的初始化程序从来没有被运行过.它已经开始,但从未完成.因此,Swift现在正在运行它 – 这恰恰意味着再次运行它.

所以,从某种意义上来说,是的,你已经把Swift与裤子一起抓住了,但是为了做到这一点,你必须做的就是这么夸张,这样可以说是你自己的错.这可能是Swift的错误,但如果是这样,这是一个在现实生活中永远不会遇到的错误.

编辑:

在WWDC 2016年Swift和并发视频中,苹果公司明确表示.在Swift 1和2中,甚至在Swift 3中,延迟实例变量不是原子的,因此如果从两个上下文同时调用,初始化程序可以运行两次 – 这正是您的代码所做的.

ios – lazy var property是否正常初始化两次?的更多相关文章

  1. three.js模拟实现太阳系行星体系功能

    这篇文章主要介绍了three.js模拟实现太阳系行星体系功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下

  2. HTML5页面无缝闪开的问题及解决方案

    这篇文章主要介绍了HTML5页面无缝闪开方案,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. ios – 为什么,将nil作为参数从Objc C发送到swift类初始化器,用新对象替换nil参数

    除非属性本身被声明为nonnull:

  4. ios – 在Swift中对MKCircle进行子类化

    我想通过添加另一个String属性来继承MKCircle,我们称之为“代码”.这个属性不是可选的和常量的,所以我必须从初始化器设置它,对吧?有没有办法定义一个单一的便利初始化器,在这种情况下需要3个参数?本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. ios – AVAudioPlayer不再使用Swift 2.0/Xcode 7 beta

    对于我的iPhone应用程序中的vartestAudio声明,我在这里收到错误“调用可以抛出,但错误不能从属性初始化程序中抛出”当我转到Xcode7测试版时,就发生了这种情况.如何在Swift2.0中使用此音频剪辑?

  6. ios – 斯威夫特.在初始化所有存储的属性之前在方法调用中使用’self’

    解决方法在初始化所有非可选实例变量之前,您无法在self上调用方法.有几种方法可以解决这个问题.>将属性更改为选项或隐式解包选项(不建议)>使buildCircle()方法静态或只是一个在文件中运行并为所有圆圈调用addSubview()在所有属性初始化并且您调用之后super.init()等等.你必须避免在自己之前打电话给自己class已初始化.

  7. ios – Objective-C警告未找到超类“-init”的指定的初始化程序的方法覆盖

    我在一个应用程序中清理警告,我收到了两次这个警告对于这行代码和这一行我相当新的Objective-C和谷歌这个警告,只是不明白的解决方案我的问题是如何摆脱这些警告?

  8. ios – UICollectionView不能使用UISearchController?

    在WWDC2014年的“AInsideInsidePresentationControllers”中,演示者展示了如何在UITableView中设置UISearchController.他们通过设置searchController的searchBar框架,然后将其设置为tableView的tableHeaderView来实现.不幸的是,UICollectionView没有相当于tableHeade

  9. ios7 – 如何使用默认的IOS映像

    嗨,我是IOS开发的新手.我知道如何在IOS应用程序中使用图像.但是我不知道如何使用默认图像,如开发者站点中提到的共享或书签图标.我想用它们我必须下载这些图像集或那些可用在xcode?

  10. ios – 在词典上引用成员’subscript’

    我正在尝试为类创建一个可用的初始化程序.我的类将使用来自网络请求的输入进行初始化.网络不可靠,我想创建一个初始化器,检查所有属性上的存在,否则它将失败.我试图在这里使用守卫,所以请随时指出方法中的任何明显的错误:守卫self.jobId行无法编译,错误:对成员’下标’的模糊引用关于如何纠正这个错误的任何想法?

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部