Archive

Monthly Archives: June 2016

Swift 3 is a reevaluation of the past 2 years and changes a lot from previous versions

Guidelines
SE-0023
https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md

Principles
– Clarity is more important than brevity on the code

Strive for clear usage, omit needless Words

From:
Too vague
friends.removeItem(ted)
friends.removeObject(ted)
friends.removeElement(ted)

And
Too specific
friends.removePerson(ted)
views.removeViews(myView)

Too
Removing needless words, if a word is not contriuting to the clarity of a usage, remove it
friends.remove(ted)
views.remove(myView)

Getting towards to having clear code that is concise

What words are needed?
myView.addChild(view, atPoint:origin)

The specification of Child is important, as it gives the context of hierarchy for the parameter

myView.addChild(view, atPoint:origin)

Since the method already gives a strong type for the parameter, the method can only recieve CGPoint, so there is no need to respecify that we are passing a point via paramter. It doens’t give additional information.

myView.addChild(view, at:origin)

 

Claryfying the behaviour of the api
By adding
friends.remove(ted) remove(_:)
friends.remove(at: formerFriendPosition) remove(at:)

In swift a method is comprised by base name “remove” as well as the argument labels. Both methods are in the same method family and they specify via the paremeter label.

In Swift you can overload methods, only if it is essentially the same operation only overloaded with different types:
text.append(aCharacter) // append(_:)
text.append(aString)

Examples where to add a parameter label, as general rule, when it helps to read well gramatically:
truck.removeBoxes(withLabel: "A label")
viewController.dismiss(animated: true)
friends.insert(michael, at: friends.startIndex)

Mutating vs non-Mutating
The “ed/ing” rule
x.reverse() //mutating
let y = x.reversed() //nonmutating

documentDirectory.appendPathComponent(".list") // mutating
let documentFile = documentDirectory.appendingPathComponent(".list") //non mutating

New API/Two Names
One name that is appropiate for Objective-C and one for Swift

Objective-C “Stringly typed” method names
in Swift 2.2:
controller.addTarget(self, action: #selector(handleDrag(sender:for)))

New in Swift 3:
Setters:
self.perform(#selector(setter: Artist.name))

Keypaths (Pound keypaths)
instead of:
album.addObserver(self, forKeyPath:"artist.name")
now:
album.addObserver(self, forKeyPath:#keypath(Album.artist.name))
Compiler validates that are Objective-c properties produces the name to pass it down to the frameworks

For mixed projects (Obj-C + Swift) some namings might not be good for one or another language

Swift
extension MyController{

@objc(handleDrag:forEvent:)
func handleDrag(sender: UIController, for event: UIEvent){} //handleDrag(sender:for) doesn’t make to much sense for Objective-c, use annotation to specify the objective-c name
}

Generated Objective-C from above

@interface MyController()
- (void)handleDragWithSender:(UIControl *)sender for:(UIEvent *)event;
@end

Translate to Swifty APIs
Automatic translations with Swift compiler
1) inspects method names and use gramatic queues to infer first parameter labels
e.g:
func saveToURL(_ url:String)
func save(toURL url:NSURL)

2) inspects names to remove reduntant information
func save(toURL url:String, forSaveOperation saveOperation: UIDocumentSaveOperation)
func save(to url:NSURL, for saveOperation:UIDocumentSaveOperation)

3) Infer default values for common objective-c idioms, like completionHandlers or option sets
func save(to url:NSURL, for saveOperation:UIDocumentSaveOperation, comletionHandler: ((Bool) -> Void)? = nil)

4) New bridging value types like URL that bridge the Objective-C Objects
func save(to url:URL, for saveOperation:UIDocumentSaveOperation, comletionHandler: ((Bool) -> Void)? = nil)

Translate “stringly” typed API to swifty (ish) API
NS_EXTENSIBLE_STRING_ENUM to transform stringly typed objective to swift
e.g
NSString *NSCalendarIdentifierGregorian = "gregorian"
to
Objective-C
typedef NSString *NSCalendarIdentifier NS_EXTENSIBLE_STRING_ENUM
NSCalendarIdentifier NSCalendarIdentifierGregorian;

Generated Swift
Transformed to Strongly typed
struct NSCalendarIdentifier: RawRepresentable{
init(_ rawValue:String)
var rawValue: String{ get }
static let gregorian:NSCalendarIdentifier
}

use
let cal = NSCalendar(identifier: .gregorian)

with bridge
let cal = Calendar(identifier: .gregorian)

Translate C API into Swifty API
NS_SWIFT_NAME import globals as members of type

C
CFStringRef kCGColorWhite NS_SWIFT_NAME(CGColor.white)
Generated Swift
extension CGColor{ static let white:CFString }
Swift use
let color = CGColor.white

C
CGAffineTransform CGAffineTranformMakeTranslation(CGFloat tx, CGFloat ty) NS_SWIFT_NAME(CGAffineTransform.init(translationX:y:));
Generated Swift
extension CGAffineTransform{ init(translationX: CGFloat, y: CGFloat) }
use
let translat = CGAffineTransform(translationX: 1.0, y: 0.5)

Complete example:

From this:

Screen Shot 2016-06-15 at 17.17.42

 

To this:

Screen Shot 2016-06-15 at 17.17.29