extreme swift

58
Swift Cam-Built Brought to you by… Movel Programming Plus

Upload: movel

Post on 07-Aug-2015

233 views

Category:

Technology


0 download

TRANSCRIPT

Swift

Cam-Built

Brought to you by…

MovelProgramming Plus

Operator Overloading

var dollarSigns = ""

for _ in 0..<3 { dollarSigns += "$" }

the normal wayRepeat a String a Specified Number of Times

var dollarSigns = "".stringByPaddingToLength(3, withString: "$", startingAtIndex: 0)

or

the extreme wayRepeat a String a Specified Number of Times

let dollarSigns = "$" * 3

Repeat a String a Specified Number of Times

let dollarSigns = "$" * 3

func * (left:String, right:Int) -> String { return right == 0 ? "" : "".stringByPaddingToLength(right, withString: left, startingAtIndex: 0) }

Function must be given global scope e.g. defined outside of a class.

Operator Overloading

the extreme way

Repeat a String a Specified Number of Timesthe extreme way with Emoji

let 🍊🍊🍊🍊🍊 = 🍊 * 5

let 🍊 = "🍎 "

print(🍊🍊🍊🍊🍊 )

?

Repeat a String a Specified Number of Timesthe extreme way

🍎🍎🍎🍎🍎

Custom Operators

normalGet a Substring of a String

var message = "[Extreme] Swift (What was Apple thinking?)”

message = message.substring(0, length: 15)

// [Extreme Swift]

Get a Substring of a String

var message = "[Extreme] Swift (What was Apple thinking?)”

message >= 15

// [Extreme Swift]

extreme

Get a Substring of a Stringextreme

infix operator <= { associativity left }

func <= (inout left:String, right:Int) { left = left.substring(0, length: right) }

var message = "[Extreme] Swift (What was Apple thinking?)”

message <= 15

// [Extreme Swift]

Pop Quiz!

var places = [Place]() var place = Place() place.address = "718 7th St. NW, Washington DC" place.name = "WeWork" place.website = "https://www.wework.com/locations/washington-d-c/chinatown" places.append(place)

place = Place() place.address = "21165 Whitfield Pl. Ste#206 Sterling, VA" place.name = "Movel" place.website = "http://www.movel.co" places.append(place)

place = Place() place.address = "One Microsoft Way Redmond, WA" place.name = "Microsoft" place.website = "http://www.microsoft.com" places.append(place)

place = Place() place.address = "4938 Hampden Lane PO Box 264, Bethesda MD" place.name = "Cam-Built" place.website = "http://www.movel.co" places.append(place)

Let’s say you have this…

class Place { var name:String? var address:String? var website:String? }

Pop QuizWhat will this do?

places -= "Microsoft"

Pop QuizYou got it!

func -= (inout left:[Place], right:String) { for index in 0..<left.count { if left[index].name == right { left.removeAtIndex(index) break } } }

Note that no infix operator needs to be defined since -= already exists.

Comparison Protocols

Include this protocol in your custom class when you want to compare instances using ==.

Equatable Protocol

Your class must implement the == operator function.

func == (left:SearchResult, right:SearchResult) -> Bool { return left.name == right.name && left.address == right.address && left.city == right.city }

class SearchResult: NSManagedObject, Equatable

You can implement more than one == operator function.

Equatable Protocol

func == (left:[String:AnyObject?], right:SearchResult) -> Bool { if let leftName = left["name"] as! String?, rightName = right.name as String? { var leftNameClean = SearchResult.cleanCompareString(leftName) var rightNameClean = SearchResult.cleanCompareString(rightName) if leftNameClean.hasPrefix(rightNameClean) ||

rightNameClean.hasPrefix(leftNameClean) { return true } else { if let leftPhone = left["phone"] as? String { if leftPhone == right.phone { return true } } } } return false }

Foursquare search results are stored in a dictionary (left) and compared with results from Yelp and TripAdvisor. If there is a match on name after cleaning punctuation and white space, Foursquare data is merged.

Pop Quiz!Which class is better?

class MeetupMembers { var members:[String]? }

class MeetupMembership { private var members = [String:String]() func addMember(name:String) { members[name] = name } func memberForKey(name:String) -> String? { return members[name] }

func memberForIndex(index:Int) -> String? { return members.keys.array[index] } }

or…

Pop QuizThe answer is the one that is most like a black box.

class MeetupMembership { private var members = [String:String]() func addMember(name:String) { members[name] = name } func memberForKey(name:String) -> String? { return members[name] }

func memberForIndex(index:Int) -> String? { return members.keys.array[index] } }

Anyone that uses MeetupMembership doesn’t have to know if “members” is an array, dictionary or any other kind of collection.

Thus, the Law of Demeter!

The Law of Demeter

Demeter is the Greek goddess of agriculture. Like plants, the Law of Demeter adheres to a bottom-up philosophy.

The ground does not offer its water to the leaves of a plant. The ground only passes the water parameter to the roots.

If you have a dog and it’s time to go walkies, you do not expect a dog’s legs to have a “walk” method. You call the dog’s “walk” method.

However, if you do not obey to the Law of Demeter, you will have less code and probably finish your projects sooner.

Swift encourages you to follow the Law of Demeter, and not just for objects but for stand-alone functions and value types.

The Swift Perspective

No Class Required// // NoClass.swift // Camtinerary // // Created by Cameron Conway on 4/26/15. // Copyright (c) 2015 cambuilt. All rights reserved. //

func helloWorld() { println("hello world") }

internal func showSecretMessage(code:String) { if code == "Abc123(*)" { println(secretMessage()) } }

private func secretMessage() -> String { return "Swift knows about AOP." }

Swift is both OO and AO (Aspect Oriented). Code files in Swift do not require a class definition, but follow the same rules of access control.

Swift Access Control

private makes a function or variable invisible to code outside of the file containing it. The benefits are that the project global namespace is kept clean and the compiler can do a better job optimizing.

internal is the default access level that makes access available across your project, but not to outside consumers of your framework or to any Objective C code.

public should be rarely used and makes access available to everybody.

Now, more about me!

Who am I?

● Learned COBOL programming on punch cards in 1985.

● dBASE III and Clipper from 1987 to 1989.

● Visual Basic from 1990 to 2000.

● C#, SQL Server, JavaScript from 2001 to present.

● Objective C from 2009 to present.

● Swift from 2014 to present.

● BASIC, Fortran and SPSS in college (American University) 1977 to 1981

“Design is not just what it looks like and feels like. Design is how it works.”

Steve Jobs, October 27 2003 as quoted in Newsweek.

Some apps that I am not.

Tripomatic

A picture is worth a thousand words. Or is it?

TripAdvisor

Lots of dots. Not much information unless you dig.

Yelp

Pins are numbered so you can cross reference. Not fun.

Foursquare

More cross referencing.

The app that is me.

Camtinerary

Microsoft Bing Image Search

Google Street View

I have lots of friends.

Search result contains content from multiple well-known sources. Pins are small and tagged with the place name to provide useful information.

Camtinerary API Code Samplesfunc searchYelp() { let client = YelpClient(consumerKey: yelpKey, consumerSecret: yelpSecret, accessToken: yelpToken, accessSecret: yelpTokenSecret) client.searchWithCategory("hotels", ll: "\(lat),\(lng)", radius:rad, offset:offset, success: { (operation: AFHTTPRequestOperation!, response: AnyObject!) -> Void in

for searchResult in jsonResult["businesses"] as! Array<NSDictionary> { yelpSearchResults.append(searchResult) ctr++ }

}) { (operation: AFHTTPRequestOperation!, error: NSError!) -> Void in println(error) } }

Using a Yelp client from GitHub and adding results to an array.

Camtinerary API Code Sampleslet url = NSURL(string: "https://api.locu.com/v2/venue/search") var request = NSMutableURLRequest(URL: url!) request.HTTPMethod = “POST"

var params = ["api_key":LOCU_API_KEY,"fields":["name", "menu_url"], “venue_queries":[["name":name,"location":["locality":city]]]]

as [String:AnyObject!] var err: NSError?

request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err) request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.addValue("application/json", forHTTPHeaderField: "Accept")

NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: { (response:NSURLResponse!, data:NSData!, error:NSError!) -> Void in

if error == nil { var err:NSError? let httpResponse = response as! NSHTTPURLResponse! if httpResponse.statusCode == 200 { if var json = NSJSONSerialization.JSONObjectWithData(data, options:

NSJSONReadingOptions.MutableContainers, error:&err) as? NSDictionary { if let venues = json["venues"] as? Array<NSDictionary> { for venue in venues { println(venue["name"]) println(venue["menu_url"]) } } } } } }) Using standard Cocoa routines for Locu data.

Driving and walking time from place to place is determined by getting directions in code using MapKit.

Camtinerary API Code Samples

let request = MKDirectionsRequest() request.setSource(MKMapItem(placemark: startMark)); request.setDestination(MKMapItem(placemark: endMark)) request.transportType = travelType; request.requestsAlternateRoutes = true let directions = MKDirections(request: request) directions.calculateDirectionsWithCompletionHandler( {(response: MKDirectionsResponse!, error: NSError!) -> () in if error == nil { if response.routes.count > 0 { let route = response.routes[0] as! MKRoute

switch travelType { case .Walking: destination.walkingTime = route.expectedTravelTime case.Automobile: destination.drivingTime = route.expectedTravelTime default: break

} Util.i.save() } } else { if !self.travelTimeError && self.refreshButtonTapped { self.travelTimeError = true self.refreshButtonTapped = false let alert = UIAlertView(title: "Travel time", message: "Travel time unavailable.",

delegate: self, cancelButtonTitle: "OK") alert.show() } } })

MapKit code for getting directions and travel times.

CLGeocoder used to get coordinates from street address. Web photos using Bing Image Search API.

Camtinerary API Code Samples

CLGeocoder().geocodeAddressString("502 Park Ave New York NY", completionHandler: {(placemarks: [AnyObject]!, error:NSError!) -> Void in

if error == nil { for placemark in placemarks as [CLPlacemark] { println(placemark.location.coordinate.longitude) println(placemark.location.coordinate.latitude) } } })

CLGeocoder for looking up coordinates with a given address.

Camtinerary API Code Sampleslet queryString = "502 Park Ave New York NY" let urlString = "https://api.datamarket.azure.com/Data.ashx/Bing/Search/Image?$format=json&Query=\(queryString)" let request = NSMutableURLRequest(URL: NSURL(string: urlString)!) let keyString = BING_SEARCH_API_KEY + ":" + BING_SEARCH_API_KEY let plainTextData = keyString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) as NSData! let base64String = plainTextData.base64EncodedStringWithOptions(.EncodingEndLineWithLineFeed) as String! request.setValue("Basic " + base64String!, forHTTPHeaderField: "Authorization")

NSURLConnection.sendAsynchronousRequest(request, queue: .mainQueue(), completionHandler: { (response:NSURLResponse!, data:NSData!, error:NSError!) -> Void in if error == nil { var err:NSError? if var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error:&err) as? NSDictionary { for result in (json["d"] as! NSDictionary)["results"] as! Array<NSDictionary> { if webURLs[result["MediaUrl"] as! String] == nil { result.setValue(false, forKey: "Selected") self.webImageURLs.append(result) } } } } }) Bing Image Search API.

Street View stills using Google Maps API.

Camtinerary API Code Samplesvar address = "502 Park Ave New York NY" var urlString = "https://maps.googleapis.com/maps/api/geocode/json?address=\(address)&key=\(GOOGLE_API_KEY)" let url:NSURL! = NSURL(string: urlString)

if url != nil { let request = NSURLRequest(URL: url) var err:NSError? NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: { (response:NSURLResponse!, data:NSData!, error:NSError!) -> Void in if error == nil {

if var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error:&err) as? NSDictionary {

var resDict = (json["results"] as! NSArray)[0] as! NSDictionary var geoDict = resDict["geometry"] as! NSDictionary var locDict = geoDict["location"] as! NSDictionary var lat = locDict["lat"] as! Double var lng = locDict["lng"] as! Double for index in 0..<4 { let url = "http://maps.googleapis.com/maps/api/streetview?location=\(lat),\(lng)&" + "size=150x150&heading=\(index * 90)" let request = NSURLRequest(URL: NSURL(string: url)!) var response:NSURLResponse?; var error:NSError? let data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error) self.streetViewImages.append(UIImage(data: data!)!) } self.photoCollectionView.reloadData() self.closeLoadingView() } } }) } Google API to retrieve StreetView photos.

Enlarged photos contained in UICollectionView object.

Using iOS 8 Share App Extensions, you share a link to this review that you found in Safari…

…with a trip and place in your itinerary.

Sharing from Camtinerary uses UIActivityController with custom UIActivity objects to email or text the entire list of search results or itinerary.

Tweet from Camtinerary and the name of selected place is included along with a Bitly version of the website URL.

“Long Touch” on a list item displays a menu to read reviews on multiple sites, restaurant menus, websites, etc.

When available, restaurant menus are displayed from Locu with lots of rich information.

Everything you didn’t know you needed to know, even Noise Level.

Includes buttons to quickly switch to different meal menus.

Options allow change in sort order, map style and price filter setting. Photos can be excluded to save cell data.

That was me.

Camtinerary

Hungry for more

Keep watching the Meetup calendar for great new events and meetings.

?

Resources

http://nshipster.com

The Swift Programming LanguageApple iBookstore

Apple Swift Blog

https://developer.apple.com/swift/blog/

iOS 8 Swift Programming Cookbook

Apple iBookstore and Barnes & Nobles

NSHipster, Second EditionObscure Topics in Cocoa & Swift