Adopting Cocoa Design Patterns
One aid in writing well-designed,resilient apps is to use Cocoa’s established design patterns. Many of these patterns rely on classes defined in Objective-C. Because of Swift’s interoperability with Objective-C,you can take advantage of these common patterns in your Swift code. In many cases,you can use Swift language features to extend or simplify existing Cocoa patterns,making them more powerful and easier to use.
Delegation
In both Swift and Objective-C,delegation is often expressed with a protocol that defines the interaction and a conforming delegate property. Just as in Objective-C,before you send a message that a delegate may not respond to,you ask the delegate whether it responds to the selector. In Swift,you can use optional chaining to invoke an optional protocol method on a possiblynil
object and unwrap the possible result usingif–let
Syntax. The code listing below illustrates the following process:
-
Check that
myDelegate
is notnil
. -
Check that
myDelegate
implements the methodwindow:willUseFullScreenContentSize:
. -
If 1 and 2 hold true,invoke the method and assign the result of the method to the value named
fullScreenSize
. -
Print the return value of the method.
-
class MyDelegate: NSObject, NSWindowDelegate {
-
func window(window: NSWindow, willUseFullScreenContentSize proposedSize: NSSize) -> NSSize {
-
return proposedSize
-
}
-
var myDelegate: NSWindowDelegate? = MyDelegate()
-
if let fullScreenSize = myDelegate?.window?(myWindow,116)"> willUseFullScreenContentSize: mySize) {
-
print(NSStringFromSize(fullScreenSize))
-
}
Alazy propertyis a property whose underlying value is only initialized when the property is first accessed. Lazy properties are useful when the initial value for a property either requires complex or computationally expensive setup,or cannot be determined until after an instance’s initialization is complete.
In Objective-C,a property may override its synthesized getter method such that the underlying instance variable is conditionally initialized if its value isnil
:
-
@property NSXMLDocument *XMLDocument;
-
-
- (NSXMLDocument *)XMLDocument {
-
if (_XMLDocument == nil) {
-
_XMLDocument = [[NSXMLDocument alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"/path/to/resource" withExtension:@"xml"] options:0 error:nil];
-
}
-
return _XMLDocument;
-
}
In Swift,a stored property with an initial value can be declared with thelazy
modifier to have the expression calculating the initial value only evaluated when the property is first accessed:
-
lazy var XMLDocument: NSXMLDocument = try! NSXMLDocument(contentsOfURL: NSBundle.mainBundle().URLForResource("document",116)"> withExtension: "xml")!,116)"> options: 0)
Because a lazy property is only computed when accessed for a fully-initialized instance it may access constant or variable properties in its default value initialization expression:
regex: NSRegularExpression = NSRegularExpression(pattern: self.pattern,116)"> options: [])
For values that require additional setup beyond initialization,you can assign the default value of the property to a self-evaluating closure that returns a fully-initialized value:
let formatter = NSDateFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
formatter
}()
NOTE
If a lazy property has not yet been initialized and is accessed by more than one thread at the same time,there is no guarantee that the property will be initialized only once.
For more information,seeLazy Stored PropertiesinThe Swift Programming Language (Swift 2.1).
Error Handling In Cocoa,methods that produce errors take anNSError
pointer parameter as their last parameter,which populates its argument with anNSError
object if an error occurs. Swift automatically translates Objective-C methods that produce errors into methods that throw an error according to Swift’s native error handling functionality.
For example,consider the following Objective-C method fromNSFileManager
:
-
- (BOOL)removeItemAtURL:(NSURL *)URL
-
error:(NSError **)error;