An introduction to the existing design patterns for using Cocoa in Swift

  • 2020-05-07 20:31:25
  • OfStack

Using some of Cocoa's existing design patterns is one of the most effective ways to help developers develop an application with sound design ideas, stable performance, and good scalability. These patterns depend on the classes defined in Objective-C. Because of the interoperability between Swift and Objective-C, you can still use these design patterns in Swift code. In some cases, you can even extend or simplify these Cocoa design patterns using Swift language features to make them more powerful and easier to use.

delegate (Delegation)

In Swift and Objective-C, delegates are typically represented by a protocol that defines the interaction methods and the delegate properties that follow the specification. In contrast to Objective-C, when you inherit a delegate in Swift, the inheritance pattern remains the same, but the internal implementation has changed. Just as in Objective-C, before you send a message to a delegate, you will check whether it is nil or not, and if the method you define is not a method that must be implemented, you will check whether the delegate implements the method or not. In Swift, these tedious and unnecessary behavior problems can be effectively eliminated by keeping the feature of type safety.

The code listed below illustrates this process:

1. Check that myDelegate is not nil.
2. Check whether myDelegate implements the inherited window:willUseFullScreenContentSize: method.
3. If myDelegate is not nil and window:willUseFullScreenContentSize: method 4 is implemented, then call the method and assign the return value of the method to a property named fullScreenSize.
Outputs the return value of the method to the console.


// @inteface MyObject : NSObject
// @property (nonatomic, weak) id<NSWindowDelegate> delegate;
// @end
if let fullScreenSize = myDelegate?.window?(myWindow, willUseFullScreenContentSize: mySize) {
    println(NSStringFromSize(fullScreenSize))
}

Note: in an app written entirely in Swift, the delegate property is defined as an NSWindowDelegate object with an indeterminate value and the initial value is set to nil.

lazy initialization (Lazy Initialization)

You can learn more about lazy initialization in Lazy Stored Properties.

error reporting (Error Reporting)

The error reporting pattern in Swift follows the pattern of Objective-C, but the new feature of variable return values in Swift gives us an additional benefit. For a very simple example, you use the Bool value as the return value of a function to indicate whether the function was successfully executed or not. When you need to print an error message, you can add an output parameter NSError of type NSErrorPointer to the function. This type is similar to NSError ** in Objective-C, with added memory security and optional arguments. You can use the ampersand operator as a prefix to pass an error message to an NSErrorPointer object that refers to an indefinite value of type NSError. The following code is shown:


var writeError : NSError?
let written = myString.writeToFile(path, atomically: false,
    encoding: NSUTF8StringEncoding,
    error: &writeError)
if !written {
    if let error = writeError {
        println("write failure: \(error.localizedDescription)")
    }
}

When you implement your method, you need to configure 1 NSErrorPointer object and set the memory attribute of NSErrorPointer object to the NSError object you created. First check the parameter passed by the caller to make sure it is an NSError object that is not nil.
Copy the new plain text window


func contentsForType(typeName: String! error: NSErrorPointer) -> AnyObject! {
    if cannotProduceContentsForType(typeName) {
        if error {
            error.memory = NSError(domain: domain, code: code, userInfo: [:])
        }
        return nil
    }
    // ...
}

Target-Action mode (Target-Action)

When a specific event occurs and one object needs to send a message to another, Cocoa's Target-Action design pattern is usually used. The Swift and Target-Action models in Objective-C are basically similar. In Swift, you can use the Selector type to achieve the selectors effect of Objective-C. See an example of using the Target-Action design pattern in Swift in Objective-C Selectors.

type matching and unification 1 specification (Introspection)

In Objective-C, you can use the isKindOfClass: method to check whether an object is of a specified type. In Swift, you can use the is operator to do this, or you can use as? Matches the specified type downward.

You can use the is operator to check whether an instance is a specified subclass. If the instance is a subclass specified, the result of the is operation is true and vice versa.


if object is UIButton {
    // object is of type UIButton
} else {
    // object is not of type UIButton
}

You can also use as. Operator tries to match the subtype down, as? The operator returns an indefinite value, used in conjunction with the if-let statement.


if let button = object as? UIButton {
    // object is successfully cast to type UIButton and bound to button
} else {
    // object could not be cast to type UIButton
}

See Type Casting for more information.

Check the match protocol syntax and check the match class syntax is 1, the following is using as? Example of checking the matching protocol:


if let dataSource = object as? UITableViewDataSource {
    // object conforms to UITableViewDataSource and is bound to dataSource
} else {
    // object not conform to UITableViewDataSource
}

Note that after the match, dataSource is converted to UITableViewDataSource, so you can only access and call the properties and methods defined by UITableViewDataSource. When you want to do something else, you have to convert it to something else.

More information can be found at Protocols.


Related articles: