Default property value with closure makes a compiler to recompile all files

白昼怎懂夜的黑 提交于 2019-12-04 11:09:56

问题


This source has a paragraph Setting a Default Property Value with a Closure or Function where we can find an example

Here’s a skeleton outline of how a closure can be used to provide a default property value:

class SomeClass {

    let someProperty: SomeType = {
         // create a default value for someProperty inside this closure
         // someValue must be of the same type as SomeType
         return someValue
    }() 
}

Well, I use it very often... Also, I often wait for the whole project to recompile after changing just one symbol. And today I have discovered that these two things are associated to each other.

Lets imagine we have some class where we set some default properties with a closure and with a function

class Class1 {

    let value: Int

    init(_ value: Int) {
        self.value = value
    }

    private lazy var lazyValueWithClosure: Int = {
        return 1111
    }()

    private lazy var lazyValueWithFunction: Int = self.getValue()

    private func getValue() -> Int {
        return 2222
    }
}

Also we have some other class in a separate file where we use the above Class1

class Class2 {

    let value: Int

    init(_ value: Int) {
        self.value = value
        _ = Class1(100)
    }
}

And some other class in a separate file where we use Class2

class Class3 {

    let value: Int

    init(_ value: Int) {
        self.value = value
        _ = Class2(100)
    }
}

and etc...

I've decided to use terminal + xcodebuild + grep to get only info about recompiled files. That is the command I use to get compilation info:

xcodebuild -scheme Test -sdk iphonesimulator -arch x86_64 -configuration Debug build OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" | grep '^[0-9]\{1,20\}.[0-9]\{1,20\}ms.*init(_ value: Int)'

That is all for preparations. Now we go to Class1 and change 2222 to some other value. Run the above command and get a result.

0.1ms   /Users/iwheelbuy/Documents/recompile/Test/Classes/Class1.swift:11:5 init(_ value: Int)

The result is good. Setting default value with functions works as expected. We have changed one file and only one file was compiled.

Then lets change the value 1111 from the Class1 to some other value and run the command. Terminal output now looks like this:

0.8ms   /Users/iwheelbuy/Documents/recompile/Test/Classes/Class5.swift:11:5 init(_ value: Int)
0.3ms   /Users/iwheelbuy/Documents/recompile/Test/Classes/Class1.swift:11:5 init(_ value: Int)
1.0ms   /Users/iwheelbuy/Documents/recompile/Test/Classes/Class4.swift:11:5 init(_ value: Int)
0.3ms   /Users/iwheelbuy/Documents/recompile/Test/Classes/Class3.swift:11:5 init(_ value: Int)
0.3ms   /Users/iwheelbuy/Documents/recompile/Test/Classes/Class2.swift:11:5 init(_ value: Int)

All the classes were recompiled... Now imagine that you have a large project and any small change in a default value closure makes you wait for the whole project to recompile.

Questions:

  • What is the reason?
  • Any suggestions how to use default value closures and not to suffer from recompilation?
  • Related to this topic?

回答1:


This is a known problem in the Swift compiler. The issue is that once you use closures or lazy properties like this, every single Swift file will be type checked. I've written a blog post on this topic which you can find here.



来源:https://stackoverflow.com/questions/41647354/default-property-value-with-closure-makes-a-compiler-to-recompile-all-files

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!