Default property value with closure makes a compil

2019-03-20 04:36发布

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条回答
时光不老,我们不散
2楼-- · 2019-03-20 05:22

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.

查看更多
登录 后发表回答