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

Switch to Swift presented at mix-it2015

Switch to Swift presented at mix-it2015

Corinne Krych

April 17, 2015
Tweet

More Decks by Corinne Krych

Other Decks in Programming

Transcript

  1. Switch to Swift?

    View Slide

  2. tweet: @corinnekrych
    code: github corinnekrych
    blog: corinnekrych.org
    chat: irc aerogear
    Corinne

    View Slide

  3. Switch to Swift?
    That is the question

    View Slide

  4. Early adoption path
    Xcode crash

    View Slide

  5. Why Swift?
    Apple goals with Swift:
    • modern
    • easy-to-read code
    • safer code
    • compatible with existing Objective-C

    View Slide

  6. Swift super powers…
    … for Switching
    to Swift

    View Slide

  7. Syntax: melting pot
    Tip 1
    "Of course, it also greatly
    benefited from the experiences hard-
    won by many other languages (…)
    Objective-C, Rust, Haskell, Ruby,
    Python, C#, CLU, and far too many
    others to list."
    Groovy
    Scala
    Rust C#
    ObjC
    Haskell

    View Slide

  8. var shoppingList = ["catfish", "water"]
    shoppingList[1] = "bottle of water"
    var occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
    ]
    occupations["Jayne"] = "Public Relations"
    var emptyMap = [:]
    var emptyList = []
    def shoppingList = ["catfish", "water"]
    shoppingList[1] = "bottle of water"
    def occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
    ]
    occupations["Jayne"] = "Public Relations"
    def emptyMap = [:]
    def emptyList = []
    Resemblance to…

    View Slide

  9. var shoppingList = ["catfish", "water"]
    shoppingList[1] = "bottle of water"
    var occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
    ]
    occupations["Jayne"] = "Public Relations"
    var emptyMap = [:]
    var emptyList = []
    def shoppingList = ["catfish", "water"]
    shoppingList[1] = "bottle of water"
    def occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
    ]
    occupations["Jayne"] = "Public Relations"
    def emptyMap = [:]
    def emptyList = []
    Resemblance to…

    View Slide

  10. Resemblance to…
    func f(x: T) -> T {...}
    func g(x: A) {}
    func h(x: T) -> T {...}
    func k(x:Int = 0) {}
    def f[T](x: T): T = ...
    def g(x: A) {}
    def h[T <: A](x: T): T ...
    def k(x: Int =0)

    View Slide

  11. Resemblance to…
    func f(x: T) -> T {...}
    func g(x: A) {}
    func h(x: T) -> T {...}
    func k(x:Int = 0) {}
    def f[T](x: T): T = ...
    def g(x: A) {}
    def h[T <: A](x: T): T ...
    def k(x: Int =0)

    View Slide

  12. Resemblance to…
    var a = "some text"
    var b = "some text"
    if a == b {
    println("The strings are equal")
    }
    if a.hasPrefix("some") {
    println("Starts with some")
    }
    if a.hasSuffix("some") {
    println("Endss with some")
    }
    a = "some text"
    b = "some text"
    if a == b:
    print("The strings are equal")
    if a.startswith("some"):
    print("Starts with some")
    if a.endswith("some"):
    print("Ends with some")

    View Slide

  13. Resemblance to…
    var a = "some text"
    var b = "some text"
    if a == b {
    println("The strings are equal")
    }
    if a.hasPrefix("some") {
    println("Starts with some")
    }
    if a.hasSuffix("some") {
    println("Endss with some")
    }
    a = "some text"
    b = "some text"
    if a == b:
    print("The strings are equal")
    if a.startswith("some"):
    print("Starts with some")
    if a.endswith("some"):
    print("Ends with some")

    View Slide

  14. Resemblance to…
    var dict = Dictionary()
    var dict2 = ["TYO": "Tokyo",
    "DUB": “Dublin"]
    for (key, value) in dict {


    }
    var dict = new Dictionary();
    var dict2 = new Dictionary
    {
    { "TYO", "Tokyo" },
    { "DUB", "Dublin" }
    };
    foreach(var item in dict) {
    var key = item.Key;
    var value = item.Value;
    }

    View Slide

  15. Resemblance to…
    var dict = Dictionary()
    var dict2 = ["TYO": "Tokyo",
    "DUB": “Dublin"]
    for (key, value) in dict {


    }
    var dict = new Dictionary();
    var dict2 = new Dictionary
    {
    { "TYO", "Tokyo" },
    { "DUB", "Dublin" }
    };
    foreach(var item in dict) {
    var key = item.Key;
    var value = item.Value;
    }

    View Slide

  16. Resemblance to…
    let success = { (res: A) -> () in
    println("succeeded")
    }
    let failure = { (res: A) -> () in
    println("FH init failed")
    }
    FH(success: success, failure: failure)
    void (^success)(A *) = ^(A * res) {
    NSLog(@"succeeded");
    };
    void (^failure)(id) = ^(A * res) {
    NSLog(@"FH init failed");
    };
    [FH initWithSuccess:success AndFailure:failure];

    View Slide

  17. Resemblance to…
    let success = { (res: A) -> () in
    println("succeeded")
    }
    let failure = { (res: A) -> () in
    println("FH init failed")
    }
    FH(success: success, failure: failure)
    void (^success)(A *) = ^(A * res) {
    NSLog(@"succeeded");
    };
    void (^failure)(id) = ^(A * res) {
    NSLog(@"FH init failed");
    };
    [FH initWithSuccess:success AndFailure:failure];

    View Slide

  18. Resemblance to…
    let success = { (res: A) -> () in
    println("succeeded")
    }
    let failure = { (res: A) -> () in
    println("FH init failed")
    }
    FH(success: success, failure: failure)
    void (^success)(A *) = ^(A * res) {
    NSLog(@"succeeded");
    };
    void (^failure)(id) = ^(A * res) {
    NSLog(@"FH init failed");
    };
    [FH initWithSuccess:success AndFailure:failure];
    http://goshdarnblocksyntax.com/

    View Slide

  19. Interactive
    Playgrounds
    Tip 2
    // Playground - noun:
    // a place where people can play

    View Slide

  20. swift
    Xcode 6.3-beta
    Xcode 6.0
    Inside Playgrounds

    View Slide

  21. swift
    Xcode 6.3-beta
    Xcode 6.0
    Inside Playgrounds

    View Slide

  22. swift
    Xcode 6.3-beta
    Inside Playgrounds

    View Slide

  23. Playground time

    View Slide

  24. To be or not to be…
    Tip 3

    View Slide

  25. 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.
    Tip 4

    View Slide

  26. /**
    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

    View Slide

  27. /**
    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

    View Slide

  28. /**
    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

    View Slide

  29. /**
    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

    View Slide

  30. Enum on steroid
    Tip 5

    View Slide

  31. var jsonString = "[{\"id\":1, \"name\": \"Eliott\"}," +
    "{\"id\":2, \"name\": \"Emilie\"}]"
    var data = jsonString.dataUsingEncoding(NSUTF8StringEncoding)
    let jsonObject: AnyObject! = NSJSONSerialization.JSONObjectWithData(data!, options:
    NSJSONReadingOptions.MutableContainers, error: nil)
    // Handling JSON in Swift with optional and type casting
    if let personsArray = jsonObject as? NSArray {
    if let firstPerson = personsArray[0] as? NSDictionary {
    if let name = firstPerson["name"] as? NSString {
    println("First person name is \(name)")
    }
    }
    }
    Problem to solve: JSON
    SwitftyJSON

    View Slide

  32. var jsonString = "[{\"id\":1, \"name\": \"Eliott\"}," +
    "{\"id\":2, \"name\": \"Emilie\"}]"
    var data = jsonString.dataUsingEncoding(NSUTF8StringEncoding)
    let jsonObject: AnyObject! = NSJSONSerialization.JSONObjectWithData(data!, options:
    NSJSONReadingOptions.MutableContainers, error: nil)
    // Handling JSON in Swift with optional and type casting
    if let personsArray = jsonObject as? NSArray {
    if let firstPerson = personsArray[0] as? NSDictionary {
    if let name = firstPerson["name"] as? NSString {
    println("First person name is \(name)")
    }
    }
    }
    Problem to solve: JSON
    SwitftyJSON
    // Using SwiftyJSON
    let json = JSON(data: data!)
    if let userName = json[0]["name"].string {
    println("First person name is \(userName)”)
    }

    View Slide

  33. public enum JSON {
    //private type number
    case ScalarNumber(NSNumber)
    //private type string
    case ScalarString(NSString)
    //private type sequence
    case Sequence([JSON])
    //private type mapping
    case Mapping([String: JSON])
    //private type null
    case Null(NSError?)
    . . .
    }
    Enum associated values
    SwitftyJSON

    View Slide

  34. public enum JSON {
    //private type number
    case ScalarNumber(NSNumber)
    //private type string
    case ScalarString(NSString)
    //private type sequence
    case Sequence([JSON])
    //private type mapping
    case Mapping([String: JSON])
    //private type null
    case Null(NSError?)
    . . .
    }
    Enum associated values
    SwitftyJSON
    public init(object: AnyObject) {
    switch object {
    case let number as NSNumber:
    self = .ScalarNumber(number)
    case let string as NSString:
    self = .ScalarString(string)
    case let null as NSNull:
    self = .Null(nil)
    case let array as [AnyObject]:
    self = .Sequence(array)
    case let dictionary as [String: AnyObject]:
    self = .Mapping(dictionary)
    default:
    self = .Null(NSError(…))
    }
    }

    View Slide

  35. SwitftyJSON
    Subscript
    // Using SwiftyJSON
    let json = JSON(data: data!)
    if let userName = json[0]["name"].string {
    println("First person name is \(userName)")
    }

    View Slide

  36. public subscript(index: Int) -> JSON {
    get {
    switch self {
    case .Sequence(let array):
    if array.count > index {
    return array[index]
    } else {
    return .Null(NSError(…))
    }
    default:
    return .Null(NSError(…))
    }
    }
    }
    SwitftyJSON
    Subscript
    // Using SwiftyJSON
    let json = JSON(data: data!)
    if let userName = json[0]["name"].string {
    println("First person name is \(userName)")
    }

    View Slide

  37. public var string: String? {
    get {
    switch self {
    case .ScalarString(let string):
    return string
    default:
    return nil
    }
    }
    }
    public subscript(index: Int) -> JSON {
    get {
    switch self {
    case .Sequence(let array):
    if array.count > index {
    return array[index]
    } else {
    return .Null(NSError(…))
    }
    default:
    return .Null(NSError(…))
    }
    }
    }
    SwitftyJSON
    Subscript
    // Using SwiftyJSON
    let json = JSON(data: data!)
    if let userName = json[0]["name"].string {
    println("First person name is \(userName)")
    }

    View Slide

  38. 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.
    Tip 6

    View Slide

  39. Functions in Swift are first-class values,
    i.e. functions may be passed as
    arguments to other functions, and
    functions may return new functions.
    Tip 7 Functions, methods
    closures

    View Slide

  40. Methods
    @implementation Greetings

    - (NSString *)helloFirstname:(NSString *)firstname lastname:(NSNumber *)lastname {
    return [[NSString alloc] initWithFormat:@"hello, %@ %@", firstname, lastname];
    }
    [self helloFirstName:@"Isabel" lastname:@"Dupont"];

    View Slide

  41. Methods
    @implementation Greetings

    - (NSString *)helloFirstname:(NSString *)firstname lastname:(NSNumber *)lastname {
    return [[NSString alloc] initWithFormat:@"hello, %@ %@", firstname, lastname];
    }
    [self helloFirstName:@"Isabel" lastname:@"Dupont"];
    class Greetings {
    func helloFirstname(firstname: String, lastname: String) -> String {
    return "Hello \(firstname) \(lastname)"
    }
    }
    let morning = Greetings()
    morning.helloFirstname("Isabel", lastname: "Dupont")

    View Slide

  42. func hello(firstname: String, lastname: String) -> String {
    return "hello, \(firstname) \(lastname)"
    }
    hello("Isabel", "Dupont")
    Functions

    View Slide

  43. func hello(firstname: String, lastname: String) -> String {
    return "hello, \(firstname) \(lastname)"
    }
    hello("Isabel", "Dupont")
    Functions
    func hello(firstname: String, #lastname: String) -> String {
    return "Hello \(firstname) \(lastname)."
    }
    hello("Isabel", lastname: "Dupont")

    View Slide

  44. func hello(firstname: String, lastname: String) -> String {
    return "hello, \(firstname) \(lastname)"
    }
    hello("Isabel", "Dupont")
    Functions
    func hello(firstname: String, #lastname: String) -> String {
    return "Hello \(firstname) \(lastname)."
    }
    hello("Isabel", lastname: "Dupont")
    func hello(firstname: String, lastname lastname: String) -> String {
    return "Hello \(firstname) \(lastname)."
    }
    hello("Isabel", lastname: "Dupont")

    View Slide

  45. Define your own matrix
    Operator overloading!
    “With great power comes great
    responsibility,”
    Tip 8

    View Slide

  46. when to use them in real life?
    Person
    {
    "firstname": "john",
    "lastname": "doe",
    "address": {
    "street": "Buch Street",
    "poBox": 123,
    "city": "Glasgow",
    "country": "UK"
    }
    }
    aerogear-ios-jsonsz

    View Slide

  47. 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
    }
    aerogear-ios-jsonsz

    View Slide

  48. 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

    View Slide

  49. 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")

    View Slide

  50. it’s all about type…
    public func <=(inout left: String?, right: JsonSZ) {
    if let value = right.value {
    field = value as? String
    }
    }
    aerogear-ios-jsonsz

    View Slide

  51. 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
    }
    }

    View Slide

  52. Go Generics
    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.”
    Tip 8

    View Slide

  53. it’s all about type…
    public func <=(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
    }
    }
    }
    aerogear-ios-jsonsz

    View Slide

  54. it’s all about type…
    public func <=(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 <=(inout left: T?, right: JsonSZ) {
    if let value = right.value as? [String: AnyObject] {
    field = JsonSZ().fromJSON(value, to: T.self)
    }
    }
    aerogear-ios-jsonsz

    View Slide

  55. Extension
    Tip 9
    Extensions add new functionality to an
    existing class, structure, or enumeration
    type.

    View Slide

  56. extension String {
    public func urlEncode() -> String {
    let encodedURL = CFURLCreateStringByAddingPercentEscapes(nil,
    self as NSString,
    nil,
    "[email protected]#$%&*'();:=+,/?[]",
    CFStringBuiltInEncodings.UTF8.rawValue)
    return encodedURL as String
    }
    }
    aerogear-ios-http
    Extend behaviour

    View Slide

  57. class MyViewController: UIViewController, UITableViewDataSource,
    UIScrollViewDelegate {
    // all methods
    }
    To be stylish ;)

    View Slide

  58. class MyViewController: UIViewController {
    // class stuff here
    }
    // MARK: - UITableViewDataSource
    extension MyViewController: UITableViewDataSource {
    // table view data source methods
    }
    // MARK: - UIScrollViewDelegate
    extension MyViewController: UIScrollViewDelegate {
    // scroll view delegate methods
    }
    class MyViewController: UIViewController, UITableViewDataSource,
    UIScrollViewDelegate {
    // all methods
    }
    To be stylish ;)

    View Slide

  59. What about testing?
    Statically Stubbed
    or
    Dynamically Mocked
    Tip 10

    View Slide

  60. 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)
    }
    aerogear-ios-oauth2

    View Slide

  61. 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)
    }
    aerogear-ios-oauth2

    View Slide

  62. 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)
    }
    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

    View Slide

  63. 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

    View Slide

  64. 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

    View Slide

  65. 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

    View Slide

  66. SwiftyJSON
    aerogear-ios-oauth2
    aerogear-ios-http
    aerogear-ios-jsonsz
    Be smart, code open source
    Dollar.swift

    View Slide