Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Switch to Swift

Corinne Krych
February 08, 2015

Switch to Swift

Switch to Swift describes our experience on AeroGear open source project when using Swift from day 1.
doSwift 2015 presentation

Corinne Krych

February 08, 2015
Tweet

More Decks by Corinne Krych

Other Decks in Programming

Transcript

  1. public func request(url: NSURL, method: HttpMethod, parameters: [String: AnyObject]?, headers:

    [String: String]? = nil) -> NSURLRequest { var request = NSMutableURLRequest(…) To be or not to be: optional if headers != nil { for (key,val) in headers! { request.addValue(val, forHTTPHeaderField: key) } } let paramSeparator = request.URL?.query != nil ? "&" : "?" if let headers = headers { for (key,val) in headers { request.addValue(val, forHTTPHeaderField: key) } } aerogear-ios-http
  2. 2. Don’t store properties Computed properties do not store a

    value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.
  3. /** An OAuth2Session implementation to store OAuth2 metadata using Keychain.

    */ public class TrustedPersistantOAuth2Session: OAuth2Session { private let keychain: KeychainWrap /** The access token. The information is read securely from Keychain. */ public var accessToken: String? { get { return self.keychain.read(self.accountId, tokenType: .AccessToken) } set(value) { if let unwrappedValue = value { let result = self.keychain.save(self.accountId, tokenType: .AccessToken, value: unwrappedValue) } } } Computed properties aerogear-ios-oauth2
  4. 3. Surrounded by clones Almost all types in Swift are

    value types, including arrays, dictionary, numbers, booleans, tuples, and enums. Classes are the exception rather than the rule.
  5. when to use them in real life? Person { "firstname":

    "john", "lastname": "doe", "address": { "street": "Buch Street", "poBox": 123, "city": "Glasgow", "country": "UK" } } class Person { var firstname: String? var lastname: String var address: Address? } class Address { var street: String var poBox: Int var city: String var country: String } class Person: JSONSerializable { var firstname: String? var lastname: String var address: Address? required init() {} class func map(source: JsonSZ, object: Person) { object.firstname <= source["firstname"] object.lastname <= source["lastname"] object.address <= source["address"] } } aerogear-ios-jsonsz // serialize from json var serializer = JsonSZ() let developer:Person = serializer.fromJSON(developerJSON, to: Person.self) XCTAssertTrue(developer.firstname == "john") XCTAssertTrue(developer.lastname == "doe")
  6. it’s all about type… public func <=(inout left: String?, right:

    JsonSZ) { if let value = right.value { field = value as? String } } aerogear-ios-jsonsz public func <=(inout left: Int?, right: JsonSZ) { if let value = right.value { field = value as? Int } } public func <=(inout left: Bool?, right: JsonSZ) { if let value = right.value { field = value as? Bool } }
  7. 5. Go Generic Generics allow a programmer to tell their

    functions and classes: “I am going to give you a type later and I want you to enforce that type everywhere I specify.” http://swiftyeti.com/
  8. it’s all about type… public func <=<T>(inout left: T?, right:

    JsonSZ) { if let value: AnyObject = right.value { switch T.self { case is String.Type, is Bool.Type, is Int.Type, is Double.Type, is Float.Type: field = value as? T . . . default: field = nil return } } } public func <=<T: JSONSerializable>(inout left: T?, right: JsonSZ) { if let value = right.value as? [String: AnyObject] { field = JsonSZ().fromJSON(value, to: T.self) } } aerogear-ios-jsonsz
  9. mocking yourself func testRequestAccessWithAuthzCodeFlow() { let expectation = expectationWithDescription("AccessRequestWithAuthzFlow"); let

    googleConfig = . . . var mock = OAuth2ModulePartialMock(config: googleConfig, session: MockOAuth2Session()) mock.requestAccess { (response: AnyObject?, error:NSError?) -> Void in XCTAssertTrue("ACCESS_TOKEN" == response as String, “response with access token") expectation.fulfill() } waitForExpectationsWithTimeout(10, handler: nil) } public class MockOAuth2Session: OAuth2Session { public override var refreshToken: String? { get {return nil} set(data) {} } public override func tokenIsNotExpired() -> Bool { return false } } class OAuth2ModulePartialMock: OAuth2Module { override func refreshAccessToken( completionHandler:(AnyObject?, NSError?) -> ()) { completionHandler("NEW_ACCESS_TOKEN", nil) } override func requestAuthorizationCode( completionHandler: (AnyObject?, NSError?) -> ()) { completionHandler("ACCESS_TOKEN", nil) } } aerogear-ios-oauth2
  10. Swizzling in Swift aerogear-ios-httpstub corinnekrych.org func testSucessfulPOST() { // set

    up http stub StubsManager.stubRequestsPassingTest({ (request: NSURLRequest!) -> Bool in return true }, withStubResponse: {(request: NSURLRequest!) -> StubResponse in let data = NSJSONSerialization.dataWithJSONObject(["key":"value"], options: nil, error: nil) return StubResponse(data: data!, statusCode: 200, headers: ["head1":"val1"]) }) var http = Http(baseURL: "http://whatever.com") // async test expectation let getExpectation = expectationWithDescription("POST http method test"); http.POST("/post", completionHandler: {(response, error) in XCTAssertNil(error, "error should be nil") XCTAssertTrue(response!["key"] as NSString == "value") getExpectation.fulfill() }) waitForExpectationsWithTimeout(10, handler: nil) }