domingo, 23 de septiembre de 2018

iOS: Interview questions and answers, and exercises

Interview questions and topics

  1. ARC and Retain cycles
  2. Communication patterns
  3. Viewcontroller lifecycle
  4. Favorite framework and why
  5. Classes vs Structs
  6. Filter, map, reduce in Collections
  7. Testing
  8. 3rd party libraries
  9. Doing an exercise with Gesture Recognizers
  10. Networking, doing a request
  11. Debugging, look at code and find bugs.
  12. Take home projects

ARC and Retain cycles

ARC tracks how many properties, constants, and variables are currently referring to each class instance. ARC will not deallocate an instance as long as at least one active reference to that instance still exists.
Whenever you assign a class instance to a property, constant, or variable, that property, constant, or variable makes a strong reference to the instance. The reference is called a strong reference when it does not allow it to be deallocated for as long as that reference remains.
Resolving retain cycles.

Communication patterns

Notifications

Its a one to many communication pattern.

Observer

Its a one to many communication pattern.

Delegate

Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object. The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate (e.g.: UITableViewDelegate) of an event that the delegating object (e.g.: UITableView) is about to handle or has just handled. The delegate may respond to the message by updating the appearance or state of itself or other objects in the application, and in some cases it can return a value that affects how an impending event is handled. The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object.

Its a one to one communication pattern.

Protocol

Its a one to one communication pattern.

ViewController lifecycle

loadView
loadViewIfNeeded
viewDidLoad
viewWillAppear
viewWillLayoutSubviews
viewdidLayoutSubviews
viewDidAppear
viewWillDisappear
viewDidDisappear

Favorite framework

CoreLocation, MapKit, UIKit, etc

Classes vs Structs

Structures and classes in Swift have many things in common. Both can:
  • Define properties to store values
  • Define methods to provide functionality
  • Define subscripts to provide access to their values using subscript syntax
  • Define initializers to set up their initial state
  • Be extended to expand their functionality beyond a default implementation
  • Conform to protocols to provide standard functionality of a certain kind
Classes have additional capabilities that structures don’t have:
  • Inheritance enables one class to inherit the characteristics of another.
  • Type casting enables you to check and interpret the type of a class instance at runtime.
  • Deinitializers enable an instance of a class to free up any resources it has assigned.
  • Reference counting allows more than one reference to a class instance.
value type is a type whose value is copied when it’s assigned to a variable or constant, or when it’s passed to a function.
In fact, all of the basic types in Swift—integers, floating-point numbers, Booleans, strings, arrays and dictionaries—are value types, and are implemented as structures behind the scenes.
All structures and enumerations are value types in Swift.
Unlike value types, reference types are not copied when they are assigned to a variable or constant, or when they are passed to a function. Rather than a copy, a reference to the same existing instance is used.
Classes are reference types.

Filter, map, reduce in Collections

filter
Returns an array containing, in order, the elements of the sequence that satisfy the given predicate.




let cast = ["Vivien", "Marlon", "Kim", "Karl"]
let shortNames = cast.filter { $0.count < 5 }
print(shortNames)
// Prints "["Kim", "Karl"]"

map
Returns an array containing the results of mapping the given closure over the sequence’s elements.




let cast = ["Vivien", "Marlon", "Kim", "Karl"]
let lowercaseNames = cast.map { $0.lowercased() }
// 'lowercaseNames' == ["vivien", "marlon", "kim", "karl"]
let letterCounts = cast.map { $0.count }
// 'letterCounts' == [6, 6, 3, 4]

flatMap
Returns an array containing the concatenated results of calling the given transformation with each element of this sequence.




let numbers = [1, 2, 3, 4]

let mapped = numbers.map { Array(repeating: $0, count: $0) }
// [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]

let flatMapped = numbers.flatMap { Array(repeating: $0, count: $0) }
// [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

compactMap
Returns an array containing the non-nil results of calling the given transformation with each element of this sequence.








let possibleNumbers = ["1", "2", "three", "///4///", "5"]

let mapped: [Int?] = possibleNumbers.map { str in Int(str) }
// [1, 2, nil, nil, 5]

let compactMapped: [Int] = possibleNumbers.compactMap { str in Int(str) }
// [1, 2, 5]

reduce
Returns the result of combining the elements of the sequence using the given closure.




let numbers = [1, 2, 3, 4]
let numberSum = numbers.reduce(0, { x, y in
    x + y
})
// numberSum == 10

Testing

Creating a Unit Test Target



  • Don't forget to add @testable import <Your Target>
  • Use XCTAsset to test models
  • Use XCTTestExpectation to test asynchronous operations

// Asynchronous test: success fast, failure slow
func testValidCallToiTunesGetsHTTPStatusCode200() {
  // given
  let url = URL(string: "https://itunes.apple.com/search?media=music&entity=song&term=abba")
  let promise = expectation(description: "Status code: 200")
  
  // when
  let dataTask = sessionUnderTest.dataTask(with: url!) { data, response, error in
    // then
    if let error = error {
      XCTFail("Error: \(error.localizedDescription)")
      return
    } else if let statusCode = (response as? HTTPURLResponse)?.statusCode {
      if statusCode == 200 {
        promise.fulfill()
      } else {
        XCTFail("Status code: \(statusCode)")
      }
    }
  }
  dataTask.resume()
  waitForExpectations(timeout: 5, handler: nil)
}

Code Coverage




3rd party libraries

Cocoapods, Carthage, etc

Doing an exercise with Gesture Recognizers

Moving a view around with a gesture


class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let rectView = UIView()
        rectView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
        rectView.backgroundColor = UIColor.green
        
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
        rectView.addGestureRecognizer(panGesture)
        
        let rotationGestureRecognizer = UIRotationGestureRecognizer(target: self, action: #selector(handleRotation(_:)))
        rectView.addGestureRecognizer(rotationGestureRecognizer)
        
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        rectView.addGestureRecognizer(tapGestureRecognizer)
        
        view.addSubview(rectView)
    }

    @objc func handlePan(_ panGesture: UIPanGestureRecognizer) {
        let translation = panGesture.translation(in: view)
        let rectView = panGesture.view
        rectView?.frame = rectView?.frame.offsetBy(dx: translation.x, dy: translation.y) ?? CGRect.zero
        panGesture.setTranslation(CGPoint.zero, in: rectView)
    }
    
    @objc func handleRotation(_ rotationGesture: UIRotationGestureRecognizer) {
        let rotation = rotationGesture.rotation
        let rectView = rotationGesture.view
        rectView?.transform = CGAffineTransform.identity.rotated(by: rotation)
    }
    
    @objc func handleTap(_ tapGesture: UITapGestureRecognizer) {
        let rectView = tapGesture.view
        
        UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseOut, animations: {
            rectView?.center.y -= 100 // If you use 'frame' rather than 'center' here if you 
            // rotate the rect first, if will get crashed
            
            UIView.animate(withDuration: 0.5, delay: 1, options: .curveEaseOut, animations: {
                rectView?.center.y += 100
            }) { (completed) in
                
            }
        }) { (completed) in
            
        }
    }
}

zoom


class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let rectView = UIView()
        rectView.frame = CGRect()
        rectView.backgroundColor = UIColor.green
        rectView.translatesAutoresizingMaskIntoConstraints = false
        
        let zoomGestureRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(handleZoom(_:)))
        rectView.addGestureRecognizer(zoomGestureRecognizer)
        
        view.addSubview(rectView)
        
        NSLayoutConstraint.activate([
            rectView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0),
            rectView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0),
            rectView.widthAnchor.constraint(equalToConstant: 100),
            rectView.heightAnchor.constraint(equalToConstant: 100)
            ])
    }

    @objc func handleZoom(_ zoomGesture: UIPinchGestureRecognizer) {
        let scale = zoomGesture.scale
        let rectView = zoomGesture.view
        rectView?.transform = CGAffineTransform.identity.scaledBy(x: scale, y: scale)
    }
}

Networking, doing a request


class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // GET
        let getUrl = URL(string: "https://www.apple.com/")!
        
        let session = URLSession.shared
        let getTask = session.dataTask(with: getUrl) { (data, response, error) in
            
            if let error = error {
                print("GET Error: ", error)
                return
            }
            
            if let httpResponse = response as? HTTPURLResponse {
                if httpResponse.statusCode == 200 {
                    print("GET Success!")
                } else {
                    print("GET Status Code: \(httpResponse.statusCode)")
                }
            }
        }
        getTask.resume()
        
        // POST
        let postUrl = URL(string: "https://httpbin.org/post")!
        
        let dictionary = ["someParameter": "value"]
        
        let request = NSMutableURLRequest(url: postUrl)
        request.httpMethod = "POST"
        request.httpBody = try? JSONSerialization.data(withJSONObject: dictionary, options: .prettyPrinted)
        
        let postTask = session.dataTask(with: request as URLRequest) { (data, response, error) in
            
            if let error = error {
                print("POST Error: ", error)
                return
            }
            
            if let httpResponse = response as? HTTPURLResponse {
                if httpResponse.statusCode == 200 {
                    print("POST Success!")
                } else {
                    print("POST Status Code: \(httpResponse.statusCode)")
                }
            }
        }
        postTask.resume()
    }
}

Debugging, look at code and find bugs

For instance, optional being unwrapped inappropriately, raise conditions in network calls, retain cycles, memory leaks, ui not updated on the main thread.

Take home projects

Networking, tableview, building a ui to a spec pixel perfect, persistance, mapkit, animations, etc. Probably will have to build the UI entirely in code. 





No hay comentarios:

Publicar un comentario