Apple's Swift has achieved the top place in Stack Overflow's "Most Loved" list of programming languages in its 2015 Developer Survey. Based on information gleaned from GitHub and Stack Overflow, analyst firm RedMonk has seen Swift's popularity ranking soar from 68 to 22 in an unprecedented 6 months.
The "Extreme Swift" event does not require advanced, or even any, knowledge of Swift. Learn about some of the more outrageous features of the language which help explain what the fuss is all about!
Never look at programming the same way again — even if you never end up writing a single line of Swift code in your life.
3. var dollarSigns = ""
for _ in 0..<3 {
dollarSigns += "$"
}
the normal way
Repeat a String a Specified Number of Times
var dollarSigns =
"".stringByPaddingToLength(3, withString: "$", startingAtIndex: 0)
or
5. 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
6. Repeat a String a Specified Number of Times
the extreme way with Emoji
let 🍊🍊🍊🍊🍊 = 🍊 * 5
let 🍊 = "🍎 "
print(🍊 🍊 🍊 🍊 🍊 )
?
7. Repeat a String a Specified Number of Times
the extreme way
🍎 🍎 🍎 🍎 🍎
9. normal
Get a Substring of a String
var message = "[Extreme] Swift (What was Apple thinking?)”
message = message.substring(0, length: 15)
// [Extreme Swift]
10. Get a Substring of a String
var message = "[Extreme] Swift (What was Apple thinking?)”
message >= 15
// [Extreme Swift]
extreme
11. Get a Substring of a String
extreme
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]
12. 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?
}
14. Pop Quiz
You 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.
16. 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
17. 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.
18. 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…
19. Pop Quiz
The 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!
21. 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.
22. However, if you do not obey to the Law of Demeter, you will
have less code and probably finish your projects sooner.
23. 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
24. 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.
25. 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.
27. 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
28. “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.
36. Search result contains content from multiple well-known sources. Pins are small and
tagged with the place name to provide useful information.
37. Camtinerary API Code Samples
func 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.
38. Camtinerary API Code Samples
let 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.
39. Driving and walking time from place to place is determined by
getting directions in code using MapKit.
40. 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.
41. CLGeocoder used to get coordinates from street address. Web
photos using Bing Image Search API.
42. 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.
43. Camtinerary API Code Samples
let 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.
45. Camtinerary API Code Samples
var 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.
57. Hungry for more
Keep watching the Meetup calendar for great new events and meetings.
?
58. Resources
http://nshipster.com
The Swift Programming Language
Apple iBookstore
Apple Swift Blog
https://developer.apple.com/swift/blog/
iOS 8 Swift Programming Cookbook
Apple iBookstore and Barnes & Nobles
NSHipster, Second Edition
Obscure Topics in Cocoa & Swift