Last active
August 29, 2015 14:26
-
-
Save JoshuaSullivan/1aaee4e7af1555153eef to your computer and use it in GitHub Desktop.
This is a Swift 2.0 Playground that demonstrates some use cases for lazy instantiation of object properties.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//: # Lazy Instantiation | |
//: | |
//: This playground demonstrates situations where lazily instantiating properties is valuable. | |
//: **NOTE:** This is a Swift 2.0 playground and must be opened in Xcode 7. | |
import UIKit | |
import CoreImage | |
//: A helper function to produce a random CGFloat in the range 0..<1 | |
func randomCGFloat() -> CGFloat { | |
return CGFloat(arc4random()) / CGFloat(UINT32_MAX) | |
} | |
class User : NSObject { | |
/// The user's name. | |
let name : String | |
/// A greeting for the user. Cannot be used until name has been set, so it's lazy. | |
lazy var greeting : String = { | |
// self must be unowned or it will create a retain cycle. | |
[unowned self] in | |
print("Generating greeting...") | |
return "Hello! My name is \(self.name)." | |
}() | |
/// A computationally intensive property. We don't want to calcualte this unless we have to! | |
lazy var avatar : UIImage = { | |
print ("Generating User avatar...") | |
// Create a couple of random colors. | |
let color0 = CIColor(red: randomCGFloat(), green: randomCGFloat(), blue: randomCGFloat()) | |
let color1 = CIColor(red: randomCGFloat(), green: randomCGFloat(), blue: randomCGFloat()) | |
// Create a CPU-driven rendering context. | |
let glContext = EAGLContext(API: EAGLRenderingAPI.OpenGLES2) | |
let ciContext = CIContext(EAGLContext: glContext) | |
// Create the basic checkerboard CIImage, guarding against failure. | |
guard let checkers = CIFilter(name: "CICheckerboardGenerator", withInputParameters: [ | |
"inputColor0" : color0, | |
"inputColor1" : color1, | |
kCIInputWidthKey : randomCGFloat() * 100.0 + 20.0] | |
)?.outputImage else { | |
// This code executes when the filter creation fails. | |
print("ERROR: Unable to create checkerboard image.") | |
return UIImage() | |
} | |
// Rotate the image to add some additional visual interest. | |
let rotation = CGAffineTransformMakeRotation(randomCGFloat() * CGFloat(M_PI)) | |
let rotatedCheckers = checkers.imageByApplyingTransform(rotation) | |
// Set up our drawing rectangle. The output size of the checkerboard is infinite, so we need to be explicit. | |
let drawRect = CGRectMake(0.0, 0.0, 200.0, 200.0) | |
// Create the output image. SWIFT BONUS: No need to manually release the returned CGImage! | |
let outputImage = ciContext.createCGImage(rotatedCheckers, fromRect: drawRect) | |
// Wrap the CGImage in a UIImage and return it. | |
return UIImage(CGImage: outputImage) | |
}() | |
/// A very simple initializer. | |
init(_ name: String) { | |
self.name = name | |
} | |
} | |
//: Create an unassuming User named "Bob". | |
let bob = User("Bob") | |
//: Accessing the property causes the creation closure to execute. | |
print(bob.greeting) | |
//: Note that you don't see the "Generating..." message a 2nd time. | |
print("Second take: \(bob.greeting)") | |
//: Accessing the property causes the creation closure to execute. Note that the print statement inside the | |
//: initialization closer occurs after the greeting on the previous line, proving that it didn't execute when the | |
//: Object was first initialized. | |
//: | |
//: Be sure to click the (+) button in the right gutter to see the actual image. | |
let avatarImage = bob.avatar | |
//: Again, note that the "Generating..." message only happens once. | |
let secondCopyOfAvatar = bob.avatar | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment