Rewrite few familiar Cocoa Touch code examples from Obj-C to Swift by learning to use Closures, Enums, Switch-Case with Pattern matching, Singleton, GCD, CoreGraphics.
Presented at Tel Aviv iOS Developers Meetup.
3. AGENDA
Rewrite few familiar Cocoa Touch code examples
from Obj-C to Swift by learning to use Closures,
Enums, Switch-Case with Pattern matching and
more.
8. Replace complex macros with functions
Swift
!
// In Foundation Module:
!
func NSLocalizedString(key: String, tableName: String? = default, bundle:
NSBundle = default, value: String = default, #comment: String) -> String
let str = NSLocalizedString("OK", comment:"comment")
9. Functions
- Default parameter values
- External parameter name used when calling the function
- Local parameter name available only in the function scope
- Shorthand external parameter names - #comment
let strError = NSLocalizedString("OK") // Error
Type '(String, tableName: String?, bundle: NSBundle, value: String, comment: String)'
does not conform to protocol 'StringLiteralConvertible'
let str334 = NSLocalizedString("OK", "") // Error
func NSLocalizedString(key: String, tableName: String? = default, bundle:
NSBundle = default, value: String = default, #comment: String) -> String
# Same external and local param name.
Useful for global functions
10. !
Methods - Functions associated with type
“Swift gives the first parameter name in a method a local parameter name by
default, and gives the second and subsequent parameter names both local and
external parameter names by default.”
class FooClass {
func updateText(text: String, color: UIColor) -> String {
return "(text) color:(color)"
}
}
!
let fc = FooClass()
fc.updateText("tlv", UIColor.blueColor())
!
!
fc.updateText("tlv", color: UIColor.blueColor()) //OK
11. What you can do with your exiting complex macros
• Replace the macros with C functions
• Create ObjC wrapper class to implement/use the macros as
functions.
• Use Swift functions with defaults
12. Closure
"Function closures capture local state variables!
(Objects are state data with attached behavior;!
Closures are behaviors with attached state data!
and without the overhead of classes.)"!
!
Peter Norvig
13. ObjC - Blocks
__block NSNumber *someVal = @10; // strong and mutable
__weak typeof(self) weakSelf = self;
!
[locationManager getCurrentLocationWithCompletion:^(CLLocation *location) {
if (!location) {
return;
}
!
if (weakSelf.completionBlock) { // Safer to use strongSelf in here
weakSelf.completionBlock(location);
}
someVal = @20;
}];
!
22. Replace if-isEqual-else with switch-case and pattern matching
if ([segue.identifier isEqualToString:@"showDetails"]) {
//…
} else if ([segue.identifier isEqualToString:"add"]) {
//…
}
ObjC
23. Replace if-isEqual-else with switch-case and pattern matching
override func prepareForSegue(segue: UIStoryboardSegue, sender: …) {
if segue.identifier == "showDetail" {
//...
} else if segue.identifier == "add" {
//..
}
}
Swift
24. Replace if-isEqual-else with switch-case and pattern matching
override func prepareForSegue(segue: UIStoryboardSegue, sender: …) {
switch segue.identifier {
case "showDetail":
//…
case "add":
//…
default: break
}
}
Swift
Switches support any kind of data and a wide variety of comparison
operations.
25. if let nvc = segue.destinationViewController as? UINavigationController {
…
}
Replace if-isEqual-else with switch-case and pattern matching
Optional binding that use optional down casting
“Try to access viewController as a navigation controller. If this is
successful, set a new temporary constant called nvc to the value
stored in the returned optional UINavigationController.”
26. Replace if-isEqual-else with switch-case and pattern matching
Another switch case pattern matching example
override func prepareForSegue(segue: UIStoryboardSegue, sender: …
{
switch segue.destinationViewController {
case let nvc as UINavigationController:
…
case let dvc as DetailsViewController:
…
default: break
}
}
28. Results Enumeration and associated value
With NSErrorPointer (NSError?)
var error : NSError?
let url = NSURL(string: "http://www.apple.com")
let data = NSData(contentsOfURL: url,
options: NSDataReadingOptions.allZeros,
error: &error)
!
if let anError = error {
println("failure: (anErrror.localizedDescription())" )
}
29. Results Enumeration and associated value
Using Enums with associated value
enum ServerResult {
case Result (NSData)
case Error (NSError)
}
!
let success = ServerResult.Result(data)
!
let failure = ServerResult.Error(NSError(domain: "MyErrorDomain", code: 1,
userInfo: nil))
switch success {
case let .Result(data):
let serverResponse = "Received data (data)"
case let .Error(error):
let serverResponse = "Failure... (error)"
}
31. Setting Defaults with ?? operator
ObjC
!!
NSString *name = text ? text : "default-name";
Swift
var text : String?
…
!
!
let name = text ?? "default-name";
33. Swift compiler gives CoreFoundation,
CoreGraphics and others ARC
/* Shape */
let pathRef = CGPathCreateMutable()
CGPathMoveToPoint(pathRef, nil, 0, 0)
CGPathAddLineToPoint(pathRef, nil, 400, 0)
CGPathAddLineToPoint(pathRef, nil, 400, 320)
CGPathAddLineToPoint(pathRef, nil, 0, 320)
CGPathAddLineToPoint(pathRef, nil, 0, 0)
CGPathCloseSubpath(pathRef)
!!
// Compiler take care memory management in most cases
So no need for these:
CGPathRelease (pathRef) or CFRelease(pathRef)
34. // In C
!
CoreGraphic Structs
CGRectMake(0, 0, 320, 480)
!
// In swift - much more readable
!
CGRect(x: 0, y: 0, width: 400, height: 320)
36. GCD a bit more cleaner
let group = dispatch_group_create()
dispatch_group_enter(group)
dispatch_group_leave(group)
dispatch_group_notify(group,dispatch_get_main_queue()) {
…
}
!
dispatch_async(dispatch_get_main_queue()) {
// trailing closure body
}
Type inferred, trailing closure
38. Singleton
You can use dispatch_once but we hope for better way
class Singleton : NSObject {
class var sharedInstance : Singleton {
struct Static {
static var onceToken : dispatch_once_t = 0
static var instance : Singleton? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = Singleton()
}
return Static.instance!
}
override init() {
println("yay");
}
}
!
Singleton.sharedInstance
39. Singleton: Replace dispatch_once with inner
struct
Class variable currently not supported (xcode 6 beta 7)
But structs do support static constants
class Singleton : NSObject {
class var sharedInstance : Singleton {
struct Static {
static let instance : Singleton = Singleton()
}
return Static.instance
}
override init() {
println("yay");
}
}
Follow https://github.com/hpique/SwiftSingleton for updates
40. References
!
- Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/il/jEUH0.l
- Apple Inc. “Using Swift with Cocoa and Objective-C.” iBooks. https://itun.es/il/1u3-0.l
- WWDC 14 Swift videos (https://developer.apple.com/videos/wwdc/2014/)
- Apple’s Dev Forums
- https://github.com/hpique/SwiftSingleton