Saturday, October 29, 2016

ios swift try, try?, try!, defer and guard

do-try-catch block
Unlike other language, the basic usage of try-catch in swift is do-try-catch block as below, the do block will only run once, so do not mix it with do-while block.

  1. var vendingMachine = VendingMachine()
  2. vendingMachine.coinsDeposited = 8
  3. do {
  4. try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
  5. } catch VendingMachineError.invalidSelection {
  6. print("Invalid Selection.")
  7. } catch VendingMachineError.outOfStock {
  8. print("Out of Stock.")
  9. } catch VendingMachineError.insufficientFunds(let coinsNeeded) {
  10. print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
  11. }
  
 try?
     As there are many cases, the operation's result is setting some value to a variable as below:

  1. let y: Int?
  2. do {
  3. y = try someThrowingFunction()
  4. } catch {
  5. y = nil
  6. }

  1. func someThrowingFunction() throws -> Int {
  2. // ...
  3. }
 
So swift introduce a simple syntax for it as try?, the above code is same as below
  1. let x = try? someThrowingFunction()


try!
When calling a throwable method, sometimes we know it will definitely not throw any exception, if so, it can be represented by try! as shown below. If, by any chance, the method does throw exception, then an runtime error will happen and terminate the app.

let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")


defer
In other language, final clause is used to execute the clean up code when leaving try-catch block. In swift, the similar function is handled by defer statement. Although defer can be used without do-try-catch block. As long as the control leaves the block where defer is defined, then the defer clause will be executed.

  1. func processFile(filename: String) throws {
  2. if exists(filename) {
  3. let file = open(filename)
  4. defer {
  5. close(file)
  6. }
  7. while let line = try file.readline() {
  8. // Work with the file.
  9. }
  10. // close(file) is called here, at the end of the scope.
  11. }
  12. }

guard

Usually at the beginning of a function, pass-in parameters are validated, and if the validation failed, the function just returns.
Use "guard" instead of "if" in case when there is a good chance the condition return true. Unlike if, guard can only have an else clause to handle negative result. Usually the else clause will return from current method execution.
Different from if let statement, the guard let variable is available after the guard clause.

guard let myValue = myOptionalValue else {
return
}
print(myValue)

catch
When catching a particular type, enum or String in swift catch block, both is or as pattern match can be used

enum errorCode : Error {
    case NoModelURL
    case NoModel
}

extension String : Error {
}

Using is pattern match sample
    do {
            let mainContext = try createMainContext()
            print("main context is \(mainContext)")
            
            let firstVC = getFirstViewController()
            firstVC.managedObjectContext = mainContext
    }
    catch errorCode.NoModel {
            print("get no model error")
        }
    catch is errorCode {
            print("Get no model url error")
        }
    catch is String {
            print("string error happened")
        }
    catch {
            print("get error \(error)")
        }

Using as pattern match sample
    do {
            let mainContext = try createMainContext()
            print("main context is \(mainContext)")
            
            let firstVC = getFirstViewController()
            firstVC.managedObjectContext = mainContext
        }
        catch errorCode.NoModel {
                print("get no model error")
        }
        catch let errCode as errorCode {
            print("Get no model url error \(errCode)")
        }
        catch let errStr as String {
            print("Get no model url error \(errStr)")
        }
        catch let e {
            print("get error \(e)")
        }
using as pattern match is better, as it can access the Error object inside the catch handler block.



Thursday, October 27, 2016

ios xcode Launch Image size and mapped name in app bundle

When creating ios project from xCode, the launchImage file name set in image asset will be automatically renamed by xcode before the image resource is added into the app bundle.

It is good to know when setting a launch image resource in xcode, what name will be mapped into the app bundle.

As ios 5, 6 is hardly used anymore, so they are not included in the below list:


iphone portrait ios 8,9
Retina HD 5.5":
Imagesize: 1242x2208
Mapped bundle name: LaunchImage-800-Portrait-736h@3x.png

Retina HD 4.7" :
Imagesize:750x1334
Mapped bundle name: LaunchImage-800-667h@2x.png

iphone landscape ios 8,9
Retina HD 5.5"  :
imagesize: 2208x1242
Mapped bundle name: LaunchImage-800-Landscape-736h@3x.png

iphone portait iOS 7-9
2x :       
image size: 640x960
Mapped bundle name:  LaunchImage-700@2x.png

Retain 4 : 
imagesize: 640x1136
Mapped bundle name: LaunchImage-700-568h@2x.png

ipad portrait ios 7-9

1x : 
image size: 768x1024
Mapped bundle name: LaunchImage-700-Portrait~ipad.png

2x : 
image size: 1536x2048
Mapped bundle name: LaunchImage-700-Portrait@2x~ipad.png

ipad Landscrape ios 7-9
1x : 
image size: 1024x768
mapped bundle name: LaunchImage-700-Landscape~ipad.png

2x : 
imagesize: 2048x1536
mapped bundle name: LaunchImage-700-Landscape@2x~ipad.png