SWIFT NOTES - PATTERN MATCHING

The original title was “SWIFT NOTES - SWITCH”, after doing some further reading and learning, I realized that it should be all about pattern matching.

But the whole story begins with the Swift switch statement for sure …

Switch Statement Features

  • No implicitly fall-through

    Unlike C, we must use the reserved word fallthrough to fallthrough into next case explicitly

  • Pattern listing

    Enumerate multiple patterns in one case statement, separated by commas , implies OR logical

  • Use where clauses to narrow down the selection further, if a binding happens in the case.

  • Matching must be exaustive

  • The most significant feature is the way to match with target data, it is so versatile and powerful that it deserves a entire section to introduce it.

Pattern Matching

Simply put, pattern matching is a mechanism (a group of syntaxes) provided by the Swift language for you to matching with a target data (record) structually, and if you want, extracts the data (field(s)) in interest at the same time.

Currently Swift defines 7 types of pattern matching, by proper use of which you can write more clear, succinct code, getting rid of spaghetti of if branches.

  1. Match traditionally – identifier matching

    value == value matching, the most common one.

  2. Wild match with a value – the wildcard pattern _

    The _ matches any thing even nil.

    Suffixing _ with a ? (_?) narrows the match range down to only those non-nil optionals. (i.e when matching with optional values, nil & _? are mutually complementary).

  3. Match with optional – value binding matching

    matching a non-nil optional and at the same time unwrap and bind a identifier to the inner value

  4. Match with tuple – tuple matching

    let or var key can appear member-wise or appear outside once

  5. Match with enum case – enum case matching

  6. Math with casted type – type-casting matching

    case is AType performs a type casting behind to see if succeed and discard the result.

    case let n as AType performs the type casting and bind the result to n for use in the case body.

  7. Match with expression – expression matching

    The most flexible one that enable you to define you own pattern.

    Match with types which implement the ~= operator, just like === operator in Ruby, where case things appear as the left hand side operand, which things as right hand side operand.

    There has been default implementations of ~= for some types such as: Range<>

    EXCEPTION: overloading ~= with a tumple as the left hand side incur panic in switch statement.

Given the aboves you could known that Swift encourages you to use optionals, tuples and enums which are smoothly fitted with pattern matching mechanism to produce a terse and clear codebase.

An Example Demonstrating All the Features Above

var aPoint = (x: 2, y: -1)
// labeled `swtich`
// NOTE: only loop statements and 'switch' statement can labeled.
theSwitch: switch aPoint {
// against tuple
case (0, 0):
  println("origin point")

// against multiple conditions separated by comma
case (1, 1), (2, 2):
  println("(1, 1) or (2, 2)")

// '_' means 'any value is ok'
case (_, 0):
  // the `break` here is just like the `pass` in python, acting as a
  // 'placeholder statement', nullifing this case branch.
  break

case (0, _):
  println("on the Y-axis")

// a expression matching nested in tuple matching
case (-2...2, -2...2):
  println("on or in the 2x2 box")

// value binding nested in tuple matching
case (let x, -10):
  println("on the horizontal line y = -10, with a x value: \(x)")

// where clause
// NOTE: `let` can be replaced with `var` if you need to change the bound
// value afterwards.
case (0, var y) where y >= 0:
  y++    // mutable
  println("on the 1st or 2nd quadrant")

// value binding all members
case let (x, y):
  theLoop: for i in 1..<100 {
    switch i {
      case let x where (x & 1) == 1: // a odd number
        break theSwitch     // jump further
      default:
        continue theLoop    // jump
    }
  }
}

References

MY AWESOME LIST - RUBY

My awesome list about the Ruby programming language

Sites

Books

COMPARE LANGUAGE I LEARNED

Swift ObjC C/C++ Python Ruby VimL Lua Go
else if else if else if else if elif elsif elseif ? ?
print print NSLog printf ? print echo ? ?
println print NSLog printf print puts echon ? ?
printf NString NString printf {} syntax printf printf ? ?
len .count .count sizeof len() .size == .count len() ? ?
inherit : : : () < ? ?
main() main() main() main() __name__ == ‘__main__‘ $0 == __FILE__ n/a ? ?
new Class() [[Class alloc] init] new Class() Class() Class.new n/a ? ?
join seq.joinWithSeparator() ? n/a sep.join(seq) seq.join(sep) join(seq, sep) ? ?
str concat str + str str str str str str + str str + str str . str str .. str ?

MY AWESOME LIST - (Neo)Vim Editor

My awesome list about the Vim(Neovim) Editor.

Sites

  • VimAwesome

    A awesome list for (Neo)Vim’s great plugins

Sripting

Test & CI

  • vim-vspec

    The old one, using RSpec syntax, needs some external dependencies

  • vader.vim

    A simple Vimscript test framework written by vim-plug’s author junegunn. It is the test framework I am using currently, it’s neat and of pure VimL

  • lua testing framework used by Neovim

    Based on the lua’s test framework busted, Neovim community have been using it for testing the Neovim project. When the lua-client comes to mature, it will be published to Neovim plugin authors. I am looking forward to it.

  • neomake

    A plugin for asynchronous :make using Neovim’s job-control functionality

  • vim-dispatch

    dispatch.vim: asynchronous build and test dispatcher, used mainly for Vim

  • vim-test

    Run your tests at the speed of thought

  • neoterm

    Wrapper of some neovim’s :terminal functions

  • vint

    Fast and Highly Extensible Vim script Language Lint implemented by Python

MY AWESOME LIST - BASH

My awesome list about the Bash programming language.

Style Guide

Coding Tools

Learning Sties

Articles

MY AWESOME LIST - SWIFT

My awesome list about the Swift programming language.

Official

Swift is Now Open Sourced

Style Guides

Coding Tools

  • SwiftLint

    Lint tool, integates into Xcode’s warnings & errors widget.

For Interviewers

  • LeetCode-Solutions-in-Swift

    1. Designed for your next iOS job interview.
    2. Optimal solutions handpicked from the LeetCode community.
    3. Best time/space complexity guaranteed.
    4. Written with the latest Swift 2.1 language features in mind.
    5. Comprehensive test cases guarding against wrong answers and timeouts.

3-Party Packages

  • iOS Cookies

    A hand curated collection of iOS libraries written in Swift

  • Readchability.swift

    Replacement for Apple’s Reachability re-written in Swift with closures

  • Venice

    CSP for Swift 2 (Linux ready)

  • jazzy

    Soulful docs for Swift & Objective-C

Networking

  • Alamofire

    HTTP networking library written in Swift

Data Handling

Package Managers

  • Carthage

    A simple, decentralized dependency manager for Cocoa.

  • CocoaPods

    The currently most popular one in community.

  • Swift Package Manager

    The Swift Package Manager is a tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.

    The official one released when Swift was open-sourced.

UI

Testing

  • Quick

    The Swift (and Objective-C) testing framework.

    Its documentation also teach new comers how to write effective tests.

  • Nimble

    A matcher framework for swift and Objective-C from Quick

Awesome Sites

  • NSHipster

    NSHipster is a journal of the overlooked bits in Objective-C, Swift, and Cocoa. Updated weekly.

    It has a Chinese translated mirror.

  • Appventure

    A personal blog about Swift, Objective-C, iOS, etc.

  • objc.io

    A Site which publishes free monthly issues covering the most important aspects of advanced iOS and OS X development.

    Treasures are in its ISSUES section.

Articles

MY AWESOME LIST - ENTRY

My internet bookmarks.

Programming Languages

Other

SWIFT NOTES - MISC

Miscellaneous knowledges I collected when learning Swift language.

Lazily stored closure property capturing self

Using implicitly unwrapped optional property to satisfying 2-phase initialization

  • it is given a default value nil automatically, it can be assigned a real initial value after delegation in initializer
  • after initialization, it can be used as a non-optional property

Only allowed in one direction

  • override read-only property -> read-write property
  • override failable initialiser -> unfailable initializer
  • failable initializer can delegate -> failable/unfailable initializer

About overriding initializer

initializer override

SWIFT NOTES - CLASS VS STRUCT & ENUM

Differences between Swift classs and structs, enums.

The most distinct difference:

  • class is reference type
  • struct & enum are value types

In general, the common things they have:

  1. can define properties, methods, subscipts
  2. can define initializers
  3. can be extended by extensions
  4. can confirm to protocols

Features exclusively owned by class

  1. inheritance
  2. deinitialization
  3. reference counting
  4. type casting

Features exclusively owned by structure

  1. memeber-wise initializer

Features exclusively owned by enum

  1. self assigning

When defining failable initializer:

  • for struct & enum, it can fail before all stored properties are given a valid initial value.
  • for class, only after the 1st initialization is completed can it fail.

You can use constant implicitly unwrapped optional property to satisfy rule #2 without first assign an valid initial value to it.

SWIFT NOTES - INITIALIZATION

Notes about Swift initialization

Syntax:

// non-failable initializer
init() {
    ...
}

// failable initializers
init?() {
    ...
}

init!() {
    ...
}

Notes:

  • Unlike normal function & methods, the 1st parameter gets a external name automatically as well as the following parameters. Use _ to suppress the external name if you want.
  • Unlike Objective-C initializers, Swift initializers do not return a value.

Setting Initial Values for Stored Properties

There are 3 ways a stored property can get an initial value:

  1. Set value in initializer
  2. Set default value in property declaration
  3. Optional stored properties get nil as default value, if given no default value

Notes:

  • Specifying a default value is preferred than set initial value in initializer.
  • Property observers will NOT be triggered by initial value setting.
  • Through closure or global function invocation syntax, you can make the default value setting more flexible.
class Foo {
    // DO NOT forget the trailling `()`, otherwise the closure/function itself
    // would be assigned to as the default value.

    let name: String = {
    ...
    }()

    var id: Int = GenerateRandomID(...)
}

Constant stored property initialization

For constant stored property, if you given a default value in definition, then it’s initialization is complete, you CAN NOT modify it’s value later in initializers.

You can define a constant stored property with no default value, and set an initial value latter in the initializers

For class instances, a constant stored property can only be modified during initialization by the class that introduces it. It cannot be modified by a subclass.

Compiler Synthesized Initializers

  1. default initializer for struct & class

    2 prerequisite:

    1. all stored property are given default values
    2. defines no custom initializer
  2. memberwise initializer for struct

    2 prerequisite

    1. defines no custom initializer
    2. defines at least one variable stored property or constant stored property that is not given a default value (so there is a necessity for the initializer)
  3. rawValue initializer for enum with associated value

    it is a failable initializer init?(rawValue: T) {...}

Initializer Delegation

Use self.init(...) to delegate initialization task to other initializers.

Since defining custom initializer suppresses default & memberwise initializer synthesization, you can define custom initializers in extension, then delegate to default or memberwise initializer in the body.

class can define 2 kinds of initializers:

  1. Designated initializers – init(...)
  2. Convenience initializers – convenience init(...)

3 rules for class initializer delegation

  1. A designated initializer must call a designated initializer from its immediate superclass.
  2. A convenience initializer must call another initializer from the same class.
  3. A convenience initializer must ultimately call a designated initializer.

put simply:

  1. Convenience initializer delegation across – self.init(...)
  2. Designated initializer delegation upwards – super.init(...)

2-Phase Initialization Ensured by 4 Safety Checks

  1. In designated initializer, initialize all local stored properties before delegate up
  2. In designated initializer, delegate up before modifying any inherited stored properties
  3. In convenience initializer, delegate across before modifying any property
  4. In any initializers, only after the 1st-phase initialization is complete then it can
    • call any instance methods or subscripts
    • read any instance properties (stored or computed)
    • reference self as an value

Initializers inheritance

Unlike subclasses in Objective-C, Swift subclasses do NOT inherit their superclass initializers by default. Only when certain rules are satisfied can certain initializers be inherited by subclasses.

Do NOT write the override modifier when providing a matching implementation of a superclass convenience initializer (because it can not delegate up to it counterpart in superclass, the implementation is not considered as a overriding)

2 prerequisites for automatic initializer inheritance

  1. If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers.
  2. If your subclass provides an implementation of all of its superclass designated initializers—either by inheriting them as per rule 1, or by providing a custom implementation as part of its definition—then it automatically inherits all of the superclass convenience initializers.

Failable Initializer

Use init?() {...} or init!() {...} to define a failable initializer

Use return nil to fail the initialization process though the Swift initializers do not return any value.

When defining failable initializer:

  • for struct & enum, it can fail before all stored properties are given a valid initial value.
  • for class, only after the 1st initialization is completed can it fail.

You can use constant implicitly unwrapped optional property to satisfy rule #2 without first assign an valid initial value to it.

Required Initializer

Write required before the definition of initiializer to indicate that every subclass of this class must implement that initiializer

The required keyword implies override in subclasses

You don’t have to provide an explicit implementation if the initiializer can be inherited

SWIFT NOTES - GUARD

guard from Swift is a branching statement similar to if, but have its own distinct use cases.

  1. Optional bound variables/constants in condition are visible after its’ guard statement.

  2. Always needs a else branch.

  3. else branch must jump out of the enclosing block of its’ guard statement. You can do it:

    • through keywords: break, continue, return, throw

    • by calling a function or method that doesn’t return, e.g. fatalError().

SWIFT NOTES - COLLECTION TYPES

Notes about Swift collection types.

Array

Type notation:

  • Full type name Array<Element>

  • Shorthand & preferred type name [Element]

Initializes an array:

  • with zero elements
// full syntax
let a = Array<Element>()

// short & preferred syntax
let a = [Element]()

// shortest syntax when the type inference is present
// `[]` here is the empty array literal with the assistence of type inference
let a: [Element] = []

func dealWith(array: [Element]) {
// ...
}

dealWith(array: [])
  • with repeated default value
// full syntax
let a = Array<Double>(count: 5, repeatedValue: 0.0)

// short & preferred syntax
let a = [String](count: 10, repeatedValue: "default text")
  • by concatenating two arrays
let a1 = [Int](count:3, repeatedValue: 0)
let a2 = [Int]()
let a = a1 + a2
  • with an array literal
let a = ["Eggs", "Oil"]
let b: [Int] = [] // is equivalent to `let b = [Int]()`

Set

Type notation:

  • Full type name Set<Element>

  • No shorthand type name for Set type

Initializes an set:

  • with no element
// full syntax
let a = Set<Element>()

// shortest syntax when the type inference is present
let a: Set<Int> = [] // same as array

func dealWith(set: Set<Int>) {
// ...
}

dealWith(set: [])
  • with an array literal
// similar with array, but must be annotated as a Set type explicitly, thus
// force converting the array literal into a set
let a: Set<String> = ["Apple", "iOS", "Mac OS X"]

// annotation can be shortened by type inference
let a: Set = [1, 2, 3]

Dictionary

Type annotation:

  • Full type name Dictionary<Key, Value>

  • Shorthand & preferred type name [Key: Value]

Initializes an array:

  • with zero elements
// full syntax
let a = Dictrionary<Key: Value>()

// short & preferred syntax
let a = [Key: Value]()

// shortest syntax when the type inference is present
// `[:]` here is the empty dictionary literal with the assistence of type inference
let a: [Key: Value] = [:]

func dealWith(array: [Key: Value]) {
// ...
}

dealWith(array: [:])

WWDC NOTES - WHAT'S NEW IN SWIFT (2015)

NOTES for What’S New in Swift (2015) from WWDC15.

Fundamentals


enum Animals {
    case Dog, Cat, Troll, Dragon
}

let a = Animals.Dragon
print(a) // get 'Animals.Dragon' instead of frustrating '(Enum Value)'

Associated Values in enums

// a stronger version of C union
enum Either<T1, T2> {
  case First(T1)
  case Second(T2)
}

Recursive enums

enum Tree(T) {
  case Leaf(T)
  indirect case Node(Tree, Tree)
}

do Statement

do {
    // new containing scope
} catch ... {

// for `do-while` in other languages, use `repeat` to avoid ambiguity
repeat {
    // repeating code lines
} while ...

Options Sets

// before swift 2.0
viewAnimationOpetions = .Repeat | .CurveEaseIn | .TransitionCurlUp
viewAnimationOpetions = nil
if viewAnimationOpetions & .TransitionCurlUp != nil {

// in swift 2.0
viewAnimationOpetions = [.Repeat, .CurveEaseIn, .TransitionCurlUp]
viewAnimationOpetions = []
if viewAnimationOpetions.contains(.TransitionCurlUp) {

// new way of defining OptionSetType derived option types
struct MyFontStyle : OptionSetType {
    let rawValue: Int
    static let Bold          = MyFontStyle(rawValue: 1)
    static let Italic        = MyFontStyle(rawValue: 2)
    static let Underline     = MyFontStyle(rawValue: 4)
    static let Strikethrough = MyFontStyle(rawValue: 8)
}

myFont.style = []
myFont.style = [.Underline]
myFont.style = [.Bold, .Italic]

if myFont.style.contains(.Strikethrough) {

Functions and Methods

all func declarations are uniform:

  • First argument is implied by the base function name

  • Labels are used for subsequent arguments

  • No special rules for defaulted parameters

  • # argument syntax has been removed

Diagnostic

  • New fix-it helps you add mutating ahead of mutating methods

  • New Warnings

    • var defined variable never mutated

    • let defined constant never used

    • unused sort() result, use in-place version sortInPlace()

SDK Improvements

Adoption of new features and best practices:

  • Nullability qualifiers

  • Objective-C typed collections

  • NS_ENUM, NS_OPTIONS, instancetype, @property, etc

see sessions:

  1. Swift and Objective-C Interoperability (2015)

  2. What’s New in Cocoa (2015)

for more details

Unit Testing and Access Control

see sessions:

  1. What’s New in Xcode (2015)

  2. UI Testing in Xcode (2015)

for more details

Rich Comments

see sessions:

  1. Authoring Rich Playgrounds (2015)

for more details

Other Features

  • Default implementations in protocols

  • C function pointers + closures

  • Recursive nested functions

  • if/do labeled break

  • SIMD Vectors

  • Mirrors API

  • readline()

  • @nonobjc

see sessions:

  1. The Swift Programming Language (Swift 2.0)

  2. Xcode 7 release notes

for more details

Pattern Matching


guard Statement for Early Exit

guard let ...
      let ... else {
}

Any variables or constants that were assigned values using an optional binding as part of the condition are available for the rest of the code block that the guard statement appears in.

The else branch must transfer control to exit the code block that that guard statement appears in. It can do this with a control transfer statement such as return, break, or continue, or it can call a function or method that dosen’t return, such as fatalError().

case Uniformly Supported in Control Flow Statements

```swift
// switch with only one case you want to handle

// before swift 2.0
switch bar() {
case .MyEnumCase(let value) where value != 42:
    doThing(value)
default: break
}

// in swift 2.0
if case .MyEnumCase(let value) = bar() where value != 42 {
    doThing(value)
}
```

for now there are 4 kind of case statements

1. switch case

1. while case

1. if case

1. guard case

1. for-in case

for ... in Filtering

```swift
// before swift 2.0
for value in mySequence {
  if value != "" {
    doThing(value)
  }
}

// in swift 2.0
for value in mySequence where value != "" {
  doThing(value)
}
```

API Availability Checking


if|guard #available({platform name} {version}, ..., *) {
  // statements to execute if the APIs are available
} else {
  // fallback statements to execute if the APIs are unavailable
}

Protocol Extensions


extension Array {

}

see sessions:

  1. Protocol Oriented Programming in Swift (2015)

for more details

Error Handling


3 New Keywords and 1 statements

  1. Fail-able functions throw errors instead of pass out inout error: NSError? (or NSErrorPointer)

  2. Use try to mark & invoke throw-able functions

  3. Use try! to assert that fail-able function must not fail.

  4. Use do {...} catch ... {} construct to try & catch errors

func mayFail() throw {
  ...
  throw {throw-able object}
  ...
}

// mark & invoke a failable function
try mayFail()

// throwing out an error is just like assertion failed
try! mayFail()

// do {
  try mayFail()
} catch ErrorEnum.ErrorType {
  // catch pattern matching
} catch let error {
  // catching & binding
} catch {
  // catch everything
}

ErrorType protocol

Any type that conforms to ErrorType can be thrown and caught

  • NSError already conforms to ErrorType

  • Can make your own types conform as well

  • Can carry data in a payload

  • Compiler handles protocol conformance details automatically

enum DataError : ErrorType {
case MissingName
case MissingYear
// add more later
}

func processSale(json: AnyObject) throws {
guard let buyerJSON = json["buyer"] as? NSDictionary {
  throw DataError.MissingBuyer
}
let buyer = try processPerson(buyerJSON)

guard let price = json["price"] as? Int {
  throw DataError.MissingPrice
}

return Sale(buyer, price)
}

defer actions

simlilar to the defer keywords in Go language.

func processSale(json: AnyObject) throws {
  delegate?.didBeginReadingSale()
  defer { delegate?.didEndReadingSale() }

  guard let buyerJSON = json["buyer"] as? NSDictionary {
    throw DataError.MissingBuyer
  }
  let buyer = try processPerson(buyerJSON)

  guard let price = json["price"] as? Int {
    throw DataError.MissingPrice
  }

  return Sale(buyer, price)
}

Swift 官博文章翻译 - 和指针类型交互

原文链接:Interacting with C Pointers

译者:Mudox

Objective-C 和 C 语言都使用到了指针类型。Swift 设计了一些数据类型,以尽可能的让您在与基于指针的 Cocoa API 交互时感到更加自然。Swift 能自动的帮您处理好很多常见的指针作为参数的情况。本文我们将好好看一看指针是怎么和 Swift 中的变量,数组和字符串类型交互的。

Swift 官博文章翻译 - 在 Swift 中实现 assert(), 第二部分:__FILE__ 和 __LINE__

原文链接:Building assert() in Swift, Part 2: __FILE__ and __LINE__

译者:Mudox

大家都知道 C 语言里有两个宏 __LINE____FILE__ 在某些场合下很有用。在编译器开始编译之前,预编译器都会将他们展开为当前的文件名和行号。尽管 Swift 没有预编译器,但是它也提供了这两个名字,并具有相同的作用,只是其运行机制截然不同。

内建的标识符

正如《Swift 语言编程指南》说所,Swift 有一些内建的标识符,其中就包括 __FLIE____LINE____COLUMN____FUNCTION__。您可以在代码中的任何地方使用他们,Swift 编译器会将他们转变成表示当前代码位置的字符串或者和整形常量。当您想要手动记录事件时,比如在退出前打印出当前代码的位置,他们会非常有用。

func assert(predicate : @autoclosure () -> Bool) {
  #if DEBUG
    if !predicate() {
      println("assertion failed at \(__FILE__):\(__LINE__)")
      abort()
    }
  #endif
}

上面的代码只会打印出 assert() 函数体内部的位置,而不是我们想要的调用它的代码的位置。

获取调用者的位置

Swift 从 D 语言那里借鉴来一个非常聪明的做法:将这些特殊的位置标识符作为参数的默认值。于是我们将 asssert() 函数定义为:

func assert(
  condition: @autoclosure () -> Bool,
  _ message: String = "",
       file: String = __FILE__,
       line: Int = __LINE__)
{
    #if DEBUG
      if !condition() {
        println("assertion failed at \(file):\(line): \(message)")
        abort()
      }
    #endif
}

函数 assert() 的第二个参数是一个可选的字符串,第三和第四个参数默认为调用代码行的位置。这样 assert() 将默认得到调用它的代码行的位置。当然您也可以在 assert() 基础上再包裹一层抽象,并将您认为合适的位置信息传主动递进 assert() 里面。比如如下的简单示例:

func logAndAssert(
  condition: @autoclosure () -> Bool,
  _ message: StaticString = "",
       file: StaticString = __FILE__,
       line: UWord = __LINE__)
{

  logMessage(message)
  assert(condition, message, file: file, line: line)
}

上面的代码中,函数 logAndAssert() 的调用位置被正确传递给 assert()。值得一提的是,我们给第二个参数使用了 StaticString 类型,他是一个和 String 类似的字符串类型,用来存储像 __FILE__ 这样展开得到的字符串,使用它没有内存管理方面的开销。

除了被用于 assert() 函数的实现外,这些功能还被用于 Swift 版的 XCTest 框架的实现中。当然,他们也可以被用于您的代码库的实现里。

Swift 官博文章翻译 - 值类型与引用类型

原文链接:Value and Reference Types

译者:Mudox

Swift 的所有类型都归于两大类:

  • 值类型,每个实例都保存着属于自己的那一份独一无二的数据,结构体 struct,枚举 enum 和元祖 tuple 都属于此类。

  • 引用类型,实例之间经常共用一份数据,类 class 就是此类型。

本文我们将探讨下他们各自的优点,以及如何在他们之间做选择。

可变性在安全性上扮演的角色

每次我们选择使用值类型而非引用类型时一个最主要的原因就是能够让代码更加清晰明了,这样我们就更容易掌控代码。如果您得到总是一份独一无二的数据拷贝,您就能确信在您的代码的其他地方不会私下改动您当前的数据。这在多线程环境中是非常有用的,因为线程经常可能在您不经意间改变了您的数据,而这种错误一旦产生又非常难排查。

由于两种类型之间的差异主要发生在修改数据时,因此当您的实例不可修改时,两者表现就完全一样了。

您可能在想某些情况下让类类型不可修改也是很有必要的呀。这样我们既能使用 Cocoa 的 NSObject 对象,又能享受到值语义的好处。今天,通过只定义只读的存储属性,以及避免暴露那些会更改状态的 API 接口,您也能用 Swift 创建出不可修改的类来。事实上,很多常用的 Cocoa 类,比如 NSURL,都被设计为不可修改的类。但是 Swift 并没有像对结构体,枚举那样,在语言层面上提供确保类不变性的机制(比如施加在子类上面)。

如何选择?

那么当您要构建一个新的类型时,您如果决定使用那种类型的语义呢?当您要使用 Cocoa 时,许多 API 都要用到 NSObject 的子类,因此您必须使用类类型。对于其他的情况,这里有一些指导建议:

使用值类型的情况:

  • 有必要用 == 来比较数据时

  • 您需要拷贝数据以获得独立的状态时

  • 数据将被用于多个线程中

使用引用类型的情况:

  • 需要用 === 来比较实例的唯一性时

  • 您需要创建共享的,可修改的状态时

在 Swift 中,数组 Array,字典 Dictionary,字符串 String 都是值类型。他们用起来就像 C 语言中简单的 int 值一样,就像每个实例都是一份独一无二的拷贝。您无需刻意去拷贝他们以防止数据被其他代码暗地里修改掉。更重要的是,在多线程之间您可以安全的传递这些值类型而无需同步措施。基于安全第一的原则,Swift 提供的这种模型能帮助您写出更加可预测的代码。

Swift 官博文章翻译 - 在 Swift 中实现 assert(),第一部分:延迟计算

原文链接:Building assert() in Swift, Part 1: Lazy Evaluation

译者:Mudox

我们在设计 Swift 语言时做出了一个关键的决断就是抛弃 C 语言的预编译器的概念,这样做不仅彻底消除了使用它可能带来的很多 bug,还让代码明了易懂。这对程序员来说是一个巨大的利好,但是它也意味着 Swift 必须用新的技术来实现一些旧的特性。大部分这样的特性的实现都很明了(模块导入,条件化编译),其中大家可能最感兴趣的就是 Swift 是如果支持类似 assert() 这样的宏定义的。

当我们在 C 语言下编译可执行文件的 release 版本时,assert() 宏并不对运行时性能有任何影响,因为它并不处理任何参数。它在 C 语言下的可能是这样实现的:

#ifdef NDEBUG
#define assert(e)  ((void)0)
#else
#define assert(e)  \
  ((void) ((e) ? ((void)0) : __assert (#e, __FILE__, __LINE__)))
#define __assert(e, file, line) \
  ((void)printf ("%s:%u: failed assertion `%s'\n", file, line, e), abort())
#endif

Swift 版的 assert() 提供和 C 版本同样的功能,没有用到预编译,而且我们以一种更加干净的方式实现了它。

实参的延迟计算

我们在实现 assert() 时,首先碰到的挑战就是在 Swift 中没有明显的方法让一个函数接受一个表达式,而不立马求它的值。比方说,我们尝试用了:

func assert(x : Bool) {
  #if !NDEBUG

    /*noop*/
  #endif
}

即使断言被禁用了,应用程序也得承担对实参表达求值的运行时开销:

assert(someExpensiveComputation() != 42)

我们或许可以通过让断言改而接受一个闭包来补救它:

func assert(predicate : () -> Bool) {
  #if !NDEBUG
    if !predicate() {
      abort()
    }
  #endif
}

被裹进闭包的表达式只有在断言被启用的情况下才会被求值:

assert({ someExpensiveComputation() != 42 })

但是这样的话,我们又不得不使用这种奇怪的调用语法:

assert({ someExpensiveComputation() != 42 })

我们可以使用 Swift 提供的属性 @autoclosure 来补救这一点。自动闭包(auto-closure)属性可以修饰函数的参数,它只是编译器自动将被修饰的实参裹进一个闭包里,就好像如下的代码:

func assert(predicate : @autoclosure () -> Bool) {
  #if !NDEBUG
    if !predicate() {
      abort()
    }
  #endif
}

它允许您这样调用断言:

assert(someExpensiveComputation() != 42)

自动闭包是一个强大的特性,它能让您有条件的计算一个表达式,甚至计算多次,就像使用闭包那样。自动闭包也被用在 Swift 的其他很多地方。比如实现短路估值(short-circuiting)的逻辑运算符,如下:

func &&(lhs: BooleanType, rhs: @autoclosure () -> BooleanType) -> Bool {
  return lhs.boolValue ? rhs().boolValue : false
}

Swift 将表达式的右操作数声明为自动闭包以让它的估值得以延迟。

自动闭包

自动闭包和 C 语言宏一样强大,所以我们必须谨慎使用它。因为使用闭包时,调用方很容易意识不到他传入的实参的求值时机被改变了。我们还限制自动闭包不接受任何参数。您不应该拿他们当某种控制流来使用。只有当用它可以实现用户预期的语义效果时,我们才使用它,而不是用它来仅仅为了消除闭包的语法的花括号。

本文探讨 Swift 实现 assert() 所使用到其中一个技术。我们还将在后续文章讨论其他的方面。

Swift 官博文章翻译 - 可为空类型案例分析:valueForKeys

原文链接:Optionals Case Study: valuesFoyKeys

译者:Mudox

本文我们将探索下可为空类型(optionals)是如果帮助 Swift 保持类型安全的。我将创建一个 Ojbective-C API 的 Swift 版本。尽管在 Swift 我们并不需要用到它,但是它确实一个有趣的例子。

在 Objective-C 中,NSDictionary 类有一个方法 objectsForKeys:notFoundMarker,它接受一个 NSArray 参数,您把要查询的键值对的键放进去,它会就把对应的值存放进另一个 NSArray 中返回。文档上说,返回的数组中的值和您存入到数组中的键是一一对应的。但是如果其中一个键在字典里没有对应的值呢?所以我们还需要传入另一个参数 notFoundMarker。对于那些在字典中没有对应值的键,objectsForKeys:notFoundMarker 会在返回的数组中用 notFoundMarker 的值来填补空位。Foundation 框架甚至为我们预定义好了一个专门表示空值的类: NSNull

在 Swift 中 Dictionary 类型并没有提供与 objectsForKeys 对应的方法。下面我们将要通过延展来给 Dictionary 类型添加这个方法。

extension Dictionary {
  func valuesForKeys(keys: [K], notFoundMarker: V) -> [V] {
    // To be implemented
  }
}

Swif 与 Objective-C 不同,它有很严格的类型检查。因此上面的方法返回的数组只能存放一种类型,所以不能用放入 NSNull 来表示空值。但是 Swift 提供了更好的解决方法:我们可以返回一组可为空值,所有的值被包裹进可为空值里。这样我们就能直接用 nil 来表示空值了。

extension Dictionary {
  func valuesForKeys(keys: [Key]) -> [Value?] {
    var result = [Value?]()
    result.reserveCapacity(keys.count)
    for key in keys {
      result.append(self[key])
    }
    return result
  }
}

你们可能已经想到为什么 Swift 的 Dictionary 不提供 objectsForKeys 方法了,因为我们可以用如下简短的代码,达到同样的效果:

extension Dictionary {
  func valuesForKeys(keys: [Key]) -> [Value?] {
    return keys.map { self[$0] }
  }
}

这就是为什么 Swift 类型总是比他们的 Objective-C 里的对应的类型提供的 API 要少很多的原因:通过 map 方法,我们可以轻松完成各种旧 API 的工作,而且有更多可能性。

现在我们来试用一下上面定义的 objectsForKeys 方法:

let dict = ["A": "Amir", "B": "Bertha", "C": "Ching"]

dict.valuesForKeys(["A", "C"])
// [Optional("Amir"), Optional("Ching")]

dict.valuesForKeys(["B", "D"])
// [Optional("Bertha"), nil]

dict.valuesForKeys([])
// []

可为空值嵌套

现在我们修改一下上面的代码,在每行后面加个 .last, 去结果集的最后一个元素:

dict.valuesForKeys(["A", "C"]).last
// Optional(Optional("Ching"))

dict.valuesForKeys(["B", "D"]).last
// Optional(nil)

dict.valuesForKeys([]).last
// nil

奇怪了,第一行代码返回了两个嵌套的可为空值。第二为 Optional(nil)。这是怎么回事呢?

还记得 .last 的定义么:

var last: T? { get }

last 是一个计算属性,其类型是可为空的元素类型。由于上面的 objectsForKeys 放回的数组的元素本身也是可为空类型,所以我们得到就是嵌套的可为空类型了。

那么 Optional(nil) 又是什么意思呢:

我们知道 Objective-C 中我们需要用 NSNull 来作为空值占位符。上面代码的 Objective-C 版本应该是:

[dict valuesForKeys:@[@"A", @"C"] notFoundMarker:[NSNull null]].lastObject
// @"Ching"

[dict valuesForKeys:@[@"B", @"D"] notFoundMarker:[NSNull null]].lastObject
// NSNull

[dict valuesForKeys:@[] notFoundMarker:[NSNull null]].lastObject
// nil

不管是在 Swift 中还是 Objective-C 中,返回 nil 都表示中间结果集为空,因为空集没有最后元素。当 Swift 的版本返回 Optional(nil) (或者 Objective-C 版本返回 NSNull )时,这表示中间结果集里是有元素的,只是这个元素表示空值。Objective-C 必须预定义一个类型 NSNull 来表示空值,而 Swift 的类型系统直接就能表示它。

提供默认值

如果您依然想用其他的值来替代字典中缺失的值呢?很容易:

extension Dictionary {
  func valuesForKeys(keys: [Key], notFoundMarker: Value) -> [Value] {
    return self.valuesForKeys(keys).map { $0 ?? notFoundMarker }
  }
}

Swift 的类型系统提供了丰富语法支持来处理一可为空类型返回的结果,而不用像 Objective-C 那样要定义一个类型来作为占位符。

Swift 官博文章翻译 - NSMethodSiganiture 发生了什么?

原文链接:What Happened to NSMethodSiganiture?

译者:Mudox

将 Cocoa 框架引入 Swift 语言带给我们一个独一无二的机会,让我们能从一个全新的角度重新审视之前的 APIs 的合理性。我们发现,多数是由于 Swift 对安全性的要求,Cocoa 框架中的一些 API 不能很好的适应 Swift。那些与动态方法调用有关的的类无法导入到 Swift 中,比如 NSInvocationNSMethodSiganiture

我们最近收到了一个开发人员的 bug 报告,他试图把他的的代码移植到 Swift,打算使用 NSMethodSiganiture 来检视方法实参的类型,结果发现 NSMethodSiganiture 并没有导入到 Swift 中。他要移植的代码需要接受不同签名的 HTTP 处理函数,比如:

func handleRequest(request: HTTPRequest, queryStringArguments: [String: String]) { }
func handleRequest(request: HTTPRequest, jsonBody: JSON) { }

在 Objective-C 中,可以用 NSMethodSiganiture 判断出第一个方法需要 [String: String] 作为实参,而第二个方法则需要 JSON 值。而 Swift 的功能十分强大,无需 NSMethodSiganiture,也不会违反编译器提供类型和内存安全性规则就能轻松处理好此类情况。下面的代码用 Swift 的方式来解决上面的问题:

struct HTTPRequest {
  // ...
}

protocol HTTPHandlerType {
  typealias Data

  /// :returns: true if the request was handled; false otherwise
  func handle(request: HTTPRequest, data: Data) -> Bool
}

我们首先声明一个协议定义处理 HTTP 请求需要满足的接口。这个协议非常简单,只有一个方法。

为什么不子类型化 HTTPHandler 呢,因为使用协议能提供更大灵活性,由用户来决定用什么来实现。如果我们定义的时一个 HTTPHandler 类,那么就会要求用户只能使用类类型,强迫他们使用引用类型。反之使用协议的换,用户可以自用的决定用什么来实现协议,用类,结构体甚至是枚举类型都可以。

class HTTPServer {
  func addHandler<T: HTTPHandlerType>(handler: T) {
    handlers.append { (request: HTTPRequest, args: Any) -> Bool in
      if let typedArgs = args as? T.Data {
        return handler.handle(request, data: typedArgs)
      }
      return false
    }
  }

  // ...
}

然后我们定义一个 HTTPServer 类,给它添加一个泛型方法,接受一个遵守 HTTPHandlerType 协议的类型参数。有了这个关联的类型参数,我们就可以通过对传入的请求数据执行条件化的向下转化来判断某个处理函数是否能处理此类数据。这就是定义协议的好处,HTTPServer 不需要知道处理器如何处理数据,甚至不需要知道它的具体类型。它只需确认这个对象有处理请求的能力(接口)就好了。

class HTTPServer {
  // ...

  private var handlers: [(HTTPRequest, Any) -> Bool] = []

  func dispatch(req: HTTPRequest, args: Any) -> Bool {
    for handler in handlers {
      if handler(req, args) {
        return true
      }
    }
    return false
  }
}

当我们的 HTTPServer 需要处理请求是,它只需便利我们的请求处理对象,看哪个能处理传入的请求和数据。

现在我们就可以轻松的创建处理各式各样类型数据的请求处理对象,并把他们注册到 HTTPServer 上。

class MyHandler : HTTPHandlerType {
  func handle(request: HTTPRequest, data: Int) -> Bool {
    return data > 5
  }
}

let server = HTTPServer()
server.addHandler(MyHandler())
server.dispatch(HTTPRequest(...), args: "x") // returns false
server.dispatch(HTTPRequest(...), args: 5)   // returns false
server.dispatch(HTTPRequest(...), args: 10)  // returns true

通过配合使用协议和泛型,我们可以用 Swift 优雅的定义处理各式各样数据类型的 HTTP 请求对象。同时也不会破坏编译器已有的安全性规则,并获得出色的运行时表现。

您可以下载本文完整的示例代码,我们把它放在了一个 Swift Playground 中。

Swift 官博文章翻译 - Swift REPL 的重定义特性

原文链接:Redefining Everything with Swift REPL

译者:Mudox

我们的之前的第一篇关于 Swift REPL 的文章只是简单的介绍了如何利用 REPL 来帮助您学习 Swift 语言的。本文将详细介绍 REPL 是如果绕过一些常规的语言编写规则来协助您开发 Swift 应用的。

重定义标识符

Swift 编译器能自动检测出大量的代码错误,其中就包括重复定义标识符。

swiftc -
var x = "The Answer"
var x = 42
^D
error: invalid redeclaration of 'x'

在一般的代码编写场景中,这是合情合理的。但是在 REPL 交互式环境中,应该让用户更加容易的修改之前的代码。我们在设计 Swift REPL 时考虑到了这一点:

  1> var x = "The Answer"
x: String = "The Answer"
  2> var x = 42
x: Int = 42
  3> x + 10
$R0: Int = 52

同一个标识符较近的定义会覆盖所有之前的定义。如上所示,您甚至可以在在下一次重复定义时改变变量的类型。重复定义方便您反复的修改优化您的代码。比如您要设计一个递归的函数:

  4> func fib(index: Int) -> Int {
  5.   if index <= 1 {
  6.     return 1
  7.   }
  8.   return fib(index - 1) + fib(index - 2)
  9. }
 10> fib(40)
$R1: Int = 165580141

这是只是这个函数的其中一种实现。在 REPL 中您可以尽情的试验用其他的算法或者 API 来实现您的函数:

 11> func fib(index: Int) -> Int {
 12.   var lastValue = 1
 13.   var currentValue = 1
 14.   for var iteration = 2; iteration <= index; ++iteration {
 15.     let newValue = lastValue + currentValue
 16.     lastValue = currentValue
 17.     currentValue = newValue
 18.   }
 19.   return currentValue
 20. }
 21> fib(40)
$R2: Int = 165580141

直接把上面的重复的函数定义敲入 REPL 中,fib 函数的定义就会被 REPL 更新。这是只是一个很简单的例子,但是它展示了 REPL 是如果方便您反复试验并改进代码的。

重定义还是重载?

我们可以在 Swift REPL 中轻松重定义常量,变量,类型还有函数,一切都很直观,方便。但是问题来了,REPL 怎么区分并让函数重定义和函数重载共存能呢?Swift REPL 只会覆盖函数名和函数签名完全都相同的函数定义。如果只是函数名相同而签名不同,那么只会引入一个函数重载。请记住,在 Swift 中就算两个函数的签名只有返回类型不同,也算是函数重载。比如:

 22> func foo() {
 23.    println("Foo!")
 24. }
 25> func foo() -> String {
 26.    return "Foo!"
 27. }
 28> foo()
error: ambiguous use of 'foo'

上面的两个函数只有返回类型不同,所以您在调用他们时必须提供足够的上下文让编译器能够推导出被调用的函数具体的返回类型(从而判断出您要调用的到底是哪个函数):

 28> var foo: String = foo()
foo: String = "Foo!"
 29> foo() as Void
Foo!

捕捉定义

尽管 REPL 允许重复定义,但是它只对后续出现的标识符有效。而之前已经被 REPL 编译过的那些代码行中的标识符引用的都还是之前的定义。这就好像新的定义只是替后面的代码遮住了旧的定义,而不是彻底的擦除了他们。下面的例子展示这个机制具体是如果运作的:

 30> var message = "Hello, World!"
message: String = "Hello, World!"
 31> func printMessage() {
 32.    println(message)
 33. }
 34> printMessage()
Hello, World!
 35> message = "Goodbye"
 36> printMessage()
Goodbye
 37> var message = "New Message"
 38> printMessage()
Goodbye
 39> println(message)
New Message

让我们一行一行的看看到底发生了什么,第 30 行我们定义了一个名为 message 的变量,里面保存的是程序员御用问候语。第 31 ~ 33 定义了一个函数 printMessage() ,它打印出第 30 行定义的变量 message 保存的问候语。我们在第 34 行调用了 printMessage() ,问候语被打印出来。到目前为止,一切都很正常。

接着我们在第 35 行对之前在第 30 行定义的 message 变量赋予新值。在第 36 行我们再次调用 printMessage() ,和我们预期的一样,打印出来的是新赋予的字符串。然后我们在第 37 行重新定义了变量 message,这样就遮住了之前的定义,让后面的代码只能看到 message 的新的定义。但是我们在 38 调用的是 printMessage() 函数, 它恰恰是在重定义 message 之前定义的,因此它保留的是 message 之前的定义,打印还是之前的字符串。 而在第 39 行,我们敲入的是新代码,它引用的自然就是重定义之后的 message

无论是函数,变量还是类型,他们在 REPL 中的重定义机制都是如此。尽管 REPL 能让您轻松的重定义标识符,但是重定义之前的被编译了的引用不会再改变。如果上面的 message 被重定义为一个类型而非变量会发生什么情况呢?printMessage 将不会再编译(这和我的实验不符,message 函数依然能被调用,打印的是之前的值)。与其每每碰到边界情况时没完没了的询问用户该怎么做,Swift REPL 努力坚持一个自我一致的世界观。

iOS NOTES - NETWORKING OPEN SOURCE FRAMEWORKS

Here records the simple usage that I learned from the 3 well-known open source networking frameworks:

  1. ASIHTTPRequest written in Objective-C language

  2. AFNetworking written in Objective-C language

  3. Alamofire written in Swift Language

All example below are run asynchronously.

Use Case #1 - Simple GET Request

1.1 With ASIHTTPRequest

Create & configure request object and emit request.

  1. create ASIHTTPRequest isntance with an NSURL.

  2. choose and set response handling scheme. ASIHTTPRequest provides 4 ways to handle responses:

    • delegation, implement the following methods (usually the first 2 are all you need) in your delegate objects, they will be called in some queue when events arrive.
    // These are the default delegate methods for request status
    // You can use different ones by setting didStartSelector / didFinishSelector / didFailSelector
    - (void)requestFinished:   (ASIHTTPRequest *)request;
    - (void)requestFailed:     (ASIHTTPRequest *)request;
    
    - (void)requestStarted:    (ASIHTTPRequest *)request;
    
    - (void)request:           (ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders;
    - (void)request:           (ASIHTTPRequest *)request willRedirectToURL:(NSURL *)newURL;
    - (void)requestRedirected: (ASIHTTPRequest *)request;
    
    
    // When a delegate implements this method, it is expected to process all incoming data itself
    // This means that responseData / responseString / downloadDestinationPath etc are ignored
    // You can have the request call a different method by setting didReceiveDataSelector
    - (void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data;
    
    • target + selector pattern, you are free to implement, in one delegate obect, more than one methods for a given event and name them arbitrarily.
    @property (assign) SEL didStartSelector;
    @property (assign) SEL didFinishSelector;
    @property (assign) SEL didFailSelector;
    
    • block, you get a succinct codebase, but should be aware of retain-circle issue. usually the first 2 are all you need.
    - (void)setCompletionBlock:                (ASIBasicBlock) aCompletionBlock;
    - (void)setFailedBlock:                    (ASIBasicBlock) aFailedBlock;
    
    - (void)setStartedBlock:                   (ASIBasicBlock) aStartedBlock;
    - (void)setHeadersReceivedBlock:           (ASIHeadersBlock) aReceivedBlock;
    - (void)setBytesReceivedBlock:             (ASIProgressBlock) aBytesReceivedBlock;
    - (void)setBytesSentBlock:                 (ASIProgressBlock) aBytesSentBlock;
    - (void)setDownloadSizeIncrementedBlock:   (ASISizeBlock) aDownloadSizeIncrementedBlock;
    - (void)setUploadSizeIncrementedBlock:     (ASISizeBlock) anUploadSizeIncrementedBlock;
    - (void)setDataReceivedBlock:              (ASIDataBlock) aReceivedBlock;
    - (void)setAuthenticationNeededBlock:      (ASIBasicBlock) anAuthenticationBlock;
    - (void)setProxyAuthenticationNeededBlock: (ASIBasicBlock) aProxyAuthenticationBlock;
    - (void)setRequestRedirectedBlock:         (ASIBasicBlock) aRedirectBlock;
    
    • subclassing subclass ASIHTTPRequest, and overwrite following methods, which is very rare occassion.
    - (void)requestFinished:(ASIHTTPRequest *)request
    - (void)requestFailed:(ASIHTTPRequest *)request
    
  3. start loading by invoking:

-(void)startSynchronous
-(void)startAsynchronous

1.1.1 Using delegation

// step #1
// initialize a instance of ASIHTTPRequest instance
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURLtrURL];

// step #2
// set delegate & selectors if you choose the target-selecors pattern
// or set blocks
// set other reqeust attributes such as progress watch, cache ...
request.delegate = self;

// step #3
// start this request operation
[request startAsynchronous];

Implement delegate methods to participate in the loading process, you choose the delegation pattern.

  1. implement requestFinished: delegate methods to fetch response content.
#pragma mark - ASIHTTPRequestDelegate
// request succeeded
- (void)requestFinished: (ASIHTTPRequest *)request
{
  // fetch response content as NSData
  NSData *data = [request responseData];

  // fetch response content as NSString
  NSString *str = [request responseString];
}
  1. implement requestFailed: delegate methods to handle failure.
// reqeust failed
- (void)requestFailed: (ASIHTTPRequest *)request
{
  NSLog(@"ERROR: %@", [request.error localizedDescription]);
}

Another alternative mentioned above is the target-selector pattern: setting selectors for success & fail handling respectively.

  [request setDidFinishSelector:@selector(requestDone:)];
  [request setDidFailSelector:@selector(requestWentWrong:)];

If you set completion selectors like above, your delegate’s completion methods will be ignored.

1.1.2 Using blocks

// step #1
//   create request instance

  // use keyword __block to make 'request' variable capturable and modifiable by blocks following
  ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];

// setp #2
//   set blocks instead of delegate to handle results

  [request setCompletionBlock:^{
     // fetching text data thought captured 'request' object
     NSString *responseString = [request responseString];

     // fetching binary data thought captured 'request' object
     NSData *responseData = [request responseData];
  }];

  [request setFailedBlock:^{
     NSError *error = [request error];
  }];

  [request startAsynchronous];
}

1.2 With AFNetworking

  1. create a manager instance.

    the AFHTTPRequestOperationManager class holds settings globally for subsequently created request operation instances.

  2. invode GET method & set everything in just one call.

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:@"http://example.com/resources.json"
  parameters:nil
     success:^(AFHTTPRequestOperation *operation, id responseObject) {
                NSLog(@"JSON: %@", responseObject);
             }
     failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                NSLog(@"Error: %@", error);
             }
];

1.3 With Alamofire

Just one call (actually a line of method chaining).

Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
         .response { (request, response, data, error) in
                     println(request)
                     println(response)
                     println(error)
                   }

Use Case #2 - Simple POST Request

With ASIHTTPRequest

Same as the above, excepts:

You should initialize a instance of ASIFormDataRequest instead of ASIHTTPRequest, which provide a bunch of extra methods to help you with composing form data body.

Set setRequestMethod: to "POST", which is inherited from ASIHTTPRequest.

For request header, you can call addRequestHeader: value: to customize request header.

For request body, you can either set it manually using ASIHTTPRequest’s methods:

- (void)setPostBody:(NSMutableData)data
- (void)appendPostData:(NSData *)data;            // body data kept in memory
- (void)appendPostDataFromFile:(NSString *)file;  // streamed from disk, suite for large content uploading

or using ASIFormDataRequests dedicated methods to compose request body:

// Using application/x-www-form-urlencoded Content-Type
- (void)setPostValue:(id <NSObject>)value forKey:(NSString *)key;
- (void)addPostValue:(id <NSObject>)value forKey:(NSString *)key;

// Using multipart/form-data Content-Type
- (void)addFile:(NSString *)filePath forKey:(NSString *)key;
- (void)addFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
- (void)setFile:(NSString *)filePath forKey:(NSString *)key;
- (void)setFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;

- (void)addData:(NSData *)data forKey:(NSString *)key;
- (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
- (void)setData:(NSData *)data forKey:(NSString *)key;
- (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;

Use Case #3 - Downlaod Task

3.1 With ASIHTTPRequest

After creating an ASIHTTPRequest instance

  • set setDownlaodDestinationPath

  • set temporaryFileDownloadPath

  • set allowResumeForFileDownloads to YES, which

tells ASIHTTPRequest not to delete partial downloads, and allows it to use an existing file to resume a download. Defaults to NO.

The names are very clarifying.

Use Case #4 - Progress Watching

4.1 With ASIHTTPRequest

First of all, set showAccurateProgress proeprty to YES, otherwise it would only notify you when a request is finished.

For simple use case, just set a UIProgressView instance as the ASIHTTPRequest’s dowloadProgressDelegate.

// on ASI request object

setDownloadProgressDelegate:
setUploadProgressDelegate:

// on delegate implement ...

// for most cases
- (void)setProgress:(float)newProgress;

Implement setProgress: delegate methods to report the download progress, if you want.

- (void)setProgress: (float)newProgress
{
  // average download speed in bytes/second
  unsigned long byte = [ASIHTTPRequest averageBandwidthUsedPerSecond];

  // current completion percent (between 0.0 ~ 1.0) from argument:
  newProgress;
}

@end

If you need more detail. ASIProgressDelegate protocol provides following methods for you to implement, whose name is rather clarifying.

- (void)request:(ASIHTTPRequest *)request didReceiveBytes:(long long)bytes;

- (void)request:(ASIHTTPRequest *)request didSendBytes:(long long)bytes;

- (void)request:(ASIHTTPRequest *)request incrementDownloadSizeBy:(long long)newLength;

- (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength;

If you ask for more details, ASIHTTPRequest provides.

Framework Office Documentation

  1. ASIHTTPRequest

  2. AFNetworking

  3. Alamofire

Swift 官博文章翻译 - 可能失败的初始化器

原文链接:Failable Initializers

译者:Mudox

Xcode 6.1 带来了 Swift 1.1,后者引入了一个新的特性:可能失败的初始化器。初始化是给类或者结构体的存储属性一个初始值,并建立起实例的不变性的过程。在某些情况下,初始化可能会失败。

比如,初始化过程需要访问某个资源(例如从文件中加载图片):

NSImage(contentsOfFile: "swift.png")

如果这个文件不存在或者处于某种原因不能访问,那么上面的 NSImage 的初始化就会失败。有了 Swift 1.1 我们可以用可能失败的初始化器(failable initializer)来报告失败的初始化操作。通过可能失败的初始化器构建对象,返回的结果被包裹在可为空类型里,如果成功就返回包含初始化了的对象的可为空值,如果失败就返回 nil。因此上面的初始化需要对返回的可为空值做拆箱操作:

if let image = NSImage(contentsOfFile: "swift.png") {
  // loaded the image successfully
} else {
  // could not load the image
}

我们可以在 Swift 的初始化器声明后加上 ! 或者 ? 后缀来表示该初始化过程会返回可为空值,且具体是那种可为空类型。比我们可以对 Int 类型增加一个可能失败的初始化器以尝试将从一个字符串中初始化出一个整形值来:

extension Int {
  init?(fromString: String) {
    if let i = fromString.toInt() {
      // Initialize
      self = i
    } else {
      // return nil, discarding self is implied
      return nil
    }
  }
}

在可能失败的初始化器中返回 nil 指示这个初始化过程失败了,因为没有其他的值可以返回。在上面的字符串初始化整型值的例子中,如果字符串不成功的被解析为一个整形数字,那么就只能返回 nil 了。如果成功,就将 self 赋值为解析出来的整型值。

可能失败的初始化器大大降低了使用工厂方法(factory methods)的必要性,在此之前我们只能用工厂方法来报告失败的对象初始化。比如那些关联了原始类型的枚举类型,他们之前都是通过一个 fromRaw 工厂类方法来返回可为空的枚举值,以报告可能失败的初始化。现在 Swift 编译器会对那些尝试从一个原始类型值映射到一个枚举值的情况自动合成一个可能失败的初始化器。

enum Color : Int {
  case Red = 0, Green = 1, Blue = 2

  // implicitly synthesized
  var rawValue: Int { /* returns raw value for current case */ }

  // implicitly synthesized
  init?(rawValue: Int) {
    switch rawValue {
      case 0: self = .Red
      case 1: self = .Green
      case 2: self = .Blue
      default: return nil
    }
  }
}

通过使用可能失败的初始化器,Swift 使其构造语法更加的统一,同时也消除了 Objective-C 中工厂方法和构造函数相互重复带来的困扰,从而大大的简化了新语言。有了可能失败的初始化器,Swift 现在把更多的带 NSError * 参数的 Cocoa 工厂方法视为初始化器处理,从而提供给用户更加统一,简洁的对象构造体验。

您可以在这里了解到更详细的关于可能失败的初始化器的内容:Swift 编程语言

Swift 官博文章翻译 - Swift REPL 交互式解释环境介绍

原文链接:Introduction to the Swift REPL

译者:Mudox

Xcode 6.1 引入了一种新的方式来体验 Swift 语言,那就是通过交互式的读取解释打印循环(Read Eval Print Loop —— REPL)。如果您之前在其他语言里用到过他,您将很快适应 Swift 的 REPL,就算是经验丰富人士在使用过程中也能发现 Swift REPL 的独到之处。

要开始使用它,请在您的 Mac OS X Yosemite 上启动 Terminal.app(在 /Applications/Utilities 里),然后打 “swift” 命令。如果您的系统是 OS X Mavericks 就打 “xcrun swift” 命令。这样您就进入了 Swift REPL 环境了:

// Welcome to Swift version 1.1 (swift-600.0.20.0). Type :help for assistance.
  1> ▌

您只需要像往常那样键入 Swift 的语句,REPL 就会马上执行您的代码。执行的结果会被自动格式化,并加上他们的类型注释(就像 Swift 的变量或者常量声明语法那样)打印在您刚刚键入的代码下:

  1> "100".toInt()
$R0: Int? = 100
  2> let name = "Katherine"
name: String = "Katherine"
  3> println("Hello, \(name)")
Hello, Katherine

Swift REPL 会将每次的计算结果存放在一个特定命名的变量里(即使您的代码并没有把计算结果赋值给具体的变量)。这样您就可以在后续的代码中引用之前的计算结果了:

 4> $R0! + 200      // 这里用 $R0 来引用上面第一行代码的计算结果
$R1: Int = 300

Swift 编译器能判断出您键入的语句是否完整,并在必要时自动提示您继续输入代码以完成语句。它甚至能像 Xcode 那样自动缩进您的代码。比如当您键入如下函数声明代码时:

5> func timesTwo() {
6.     ▌

这里第 6 行为续行提示符(数字后跟一个点),这样您一眼就能明白 REPL 需要您继续键入剩余的代码。此时您可以继续键入余下的代码:

5> func timesTwo() {
6.      return value * 2
7. }▌

这里有三点值得说明下:

  • 首先 REPL 在第 6 行自动缩进了代码,当我们在第 7 行键入 } 后,REPL 又帮您自动缩进回来。

  • 其次,我们在函数体内引用了一个我们忘了声明的变量名 value,并且函数也忘了声明返回类型,您需要把这两个都加上。

  • 最后,就算您忘了添加变量声明和返回类型声明而按下了回车键,这也不会太晚,REPL 还能给您挽救的机会。

多行历史记录

您的代码被提交给编译器的同时,也会被 REPL 环境记录下来。这使得您能更加轻松的修改之前的代码。接着上面的代码,如果您按下回车键就会得到如下的提示:

error: use of unresolved identifier 'value'

和其他环境下的历史记录功能使用方法一样,您可以按下 键来调出之前出入过的代码行。REPL 一次性把我们上面输入的三行代码全部调了出来,并将光标放在的最后一行的末尾。按照下节的指引您就能更正之前的错误了。

每次会话保存的历史记录是能够保留到下次会话的,总共能保存上几百段代码。您可以从代码的首行按向上键(或者 Ctrl+P)调出更早输入的代码,也可以从最后一行代码下面的空行上按 键调出稍近的代码。我们将在下面解释为什么最后一行往下还会出现一行空行。

多行编辑

尽管 Swift REPL 环境表现得像传统的命令行编辑器,它还是提供了多行编辑的能力,这样像输入类定义,函数定义这样经常需要多行一起输入的情况,编辑起来就变得简单了。在上面的函数定义的示例中,在您在最后一行尾按下回车键之前,您可以按下 将光标移动到上面的行,并使用 键移动到参数列表的 ( 后面来修改,添加参数:

5> func timesTwo(▌ {
6.     return value * 2
7. }

现在键入参数声明,然后按 键移动到 ( 之后,然后加上返回类型声明:

5> func timesTwo(value: Int) -> Int▌  {
6.              return value * 2
7. }

在代码中间按下回车键是不能结束代码输入,提交 REPL 的。在中间按回车键只能插入新的一行以便您想在函数或者方法体内加入新行。您这里想要的是移动光标到代码最末尾,您可以按 键两次,或者使用 Emacs 的按键序列 Esc > (Esc 键之后跟一个左尖括号)。在最末尾按下回车键就能将新修改的函数定义提交了:

  8>  timesTwo(21)
$R2: (Int) = 42

自动侦测语句完整性意味着大多数情况下您只管输入心中的代码,让 REPL 来干剩下的脏活。但是某些情况下,您需要一次提交多个语句,因为他们之间相互依赖。设想有下面的代码:

func foo() {
  bar()
}
func bar() {
  foo()
}

如果您只是一行一行的输入上面的代码,当您输入完第三行代码之后就为把第一个函数提交给 REPL 执行,自然会得到如下的警告:

error: use of unresolved identifier 'bar'

当然您可以一行定义两个函数,两个语句之间用分号隔开,但是还有一个更好的方法。在您输入完第三行之后按下 键就会插入并移动到第四行,这是您再就可以继续输入第二个函数的声明了。这两个语句被一次性提交给编译器,达到相互递归的意图。

快速参考

为了帮助你快速开始使用 Swift REPL 环境,面给了常用的编辑和导航快捷键:

按键组合 注释
方向键 上下左右移动光标
Control + F 向右移动光标一个字符,和按下 键一样
Control + B 向左移动光标一个字符,和按下 键一样
Control + P 向上移动光标一个字符,和按下 键一样
Control + N 向下移动光标一个字符,和按下 键一样
Control + D 删除光标键下的字符
Option + Left 将光标移动到上一个单词的开始处
Option + Right 将光标移动到下一个单词的开始处
Control + A 将光标移动到本行首
Control + E 将光标移动到本行末
Delete 删除光标前面的一个字符(这里指主键盘区的回退键 Backspace)
Esc < 将光标移动到第一行的行首
Esc > 将光标移动到最后一行的行末

Swift 官博文章翻译 - Swift 1.2 和 Xcode 6.3 新特性介绍

原文链接:Swift 1.2 and Xcode 6.3 beta

译者:Mudox

Xcode 6.3 beta 给我们带来了 Swift 1.2 beta 版。不仅 Swift 编译器性能得到显著提升,还带了很多新的 Swift 语言特性。 如需了解全部的变更,请参阅本次的版本说明。本文将着重介绍其中的若干亮点。

编译器改进

Swift 1.2 的编译器变得更加稳定,并全面提升了编译器性能。同时它能带来了诸多特性能是您再 Xcode 中使用 Swift 时有更好的体验。其中一些明显的改进包括:

  • 增量构建

    默认情况下编译器不会再重复编译没有改变过的源文件,这将使绝大多数情况下的编译时间大大缩短。当然,如果您对代码结构做了大规模的改动后,依然可能导致编译器编译多个文件。

  • 生成更加快速的代码

    Debug 和 Release 模式下生成的可执行文件的运行速度都大大提升了。

  • 更强大的编译诊断能力

    增强的 Fix-its 功能,能帮助您扫除各种错误和警告,从而写出正确的 Swift 1.2 代码。

  • 稳定性提升

    我们修复了大多数用户常见的 SourceKit 警告。您将不再被此类提示困扰。

新的语言特性

在 1.2 中我们进一步改善了 Swift 语言,使之更加安全,可预测。我们继续改进 Swift 和 Objective-C 之间的交互。其中一些显著的进步包括:

  • 新的 as! 运算符来表示可能失败的类型转换

    那些在运行时不一定成功的类型转换必须明确的用 as! 来表示。从而使得代码的意图和后或对后续的阅读者和维护人员更加明了。

  • 可以在 Objective-C 头文件中添加可为空性注释

    Clang 中引入了一个新的 Objective-C 语言扩展,能再您的 Objective-C API 中明确标注出指针和块引用的可为空性。这样您就能写出与 Swift 交互的更好的 Objective-C 框架,同时使您在项目中混用 Objective-C 和 Swift 的代码时能获得更好的性能。

  • Swift 枚举类型现在可以通过 @objc 修饰来导出到 Objective-C 中

    比如如下的 Swift 代码:

    @objc enum Bear: Int {
      case Black, Grizzly, Polar
    }
    

    导入到 Objective-C 中为:

    typedef NS_ENUM(NSInteger, Bear) {
      BearBlack, BearGrizzly, BearPolar
    };
    
  • 更加强大,一致的 let 关键字 i

    新规则规定 let 常量必须在第一次使用前被初始化(和 var 变量类似),并且之后不能被重新赋值或者修改。

    这将允许我们写出如下的代码:

    let x : SomeThing
    if condition {
      x = foo()
    } else {
      x = bar()
    }
    use(x)
    

    在这之前为了达到这个效果,我们只能使用 var 来声明(尽管初始化后就再没有代码改动它)。同样的,常量属性也可以这样声明,然后再初始化器中初始化。

  • 更加的强大的可为空类型条件拆箱 if let

    if let 语句现在能一次拆箱多个可为空变量,还可以在其中插入布尔条件表达式。这可以让您无需嵌套也能表达复杂的条件拆箱控制逻辑。

  • 新的原生的集合 Set 数据类型

    Set 是一个和 NSSet 完美桥接的数据类型,用来表示一组无序的,唯一的数据。和 ArrayDictionary 一样,它在 Swift 中是一个值而非引用。

总结

我们由衷的欢迎您提交任何 bug 报告,希望所有常见的问题都在这个 beta 版得到解决。Swift 1.2 对于语言本身和其工具来说都是一次巨大的改进。它也引入了一些不向后兼容的改动,需要您对之前的代码做出修改,因此 Xcode 6.3 包含了一个移植工具来帮助您自动化这个过程。要使用该工具,请选 Edit 菜单,然后选择 Convert -> To Latest Swift Syntax… 选项。

iOS NOTES - iOS ANIMATIONS

iOS Animation API Clusters From Top to Bottom

In general there are 2 groups of APIs: the view based animation APIs & the underlying Core Animation APIs that is backing the former.

  1. UIView begin... & commit... style APIs

    They are the oldest APIs before block was introduced into the framework, with begin... to start recording an animation, a bunch of setAnimation... to be called subsequently to set configure various animations detailes, and then ends with a commit... call.

  2. UIView block based APIs

    In iOS 4.0, block was introduced to facilitates the creation of UIView animations (replacing the old begin... & commit APIs).

    Note that during the animation block, you can still call the setAnimation... functions to tweak details of animation.

    The full form of the function accepts 5 arguments:

    1. Duration

    2. Delay

    3. Animation options

    4. The animation block

    5. Completion block

    The block based animation is just like creating, configuring & adding CABasicAnimation to layers of each involved view in the block.

  3. UIView spring Animation

    As its name suggests, it can do some kind of underdamped oscillation. It arguments list is similar to full form of block based function, with two more paramters:

    1. Damping ratio

    2. Initial velocity

  4. UIView view transition APIs

    2 convenient methods were added to faciliate the common occasions when you want to animation subview changes in one view a whole, or replacing one view with another.

  5. UIView key frame Based APIs

    It only have 2 methods, call animateKeyframes... to start the whole animation, and within a block, call addKeyframe... multiple times with apprioate relative timming setting to layout the key frames duraing the whole animation.

    Using it is just like adding CAKeyframeAnimation to the layer of involved views in the block.

  6. Core Animation

    Provided by the Quartz Core framework from Media Layer. It is the basis of everything mentioned above.

    It provides concepts of layer, animcation object, animation transaction, etc. When you can not achieve effect you want through APIs listed above, come for it.

Swift 官博文章翻译 - as! 运算符

原文链接:The as! Operator

译者:Mudox

在 Swift 1.2 之前,as 运算符可以用来完成两种不同类型转换操作。取决要转换的表达式的类型,和要转化到的类型,as 运算符可以完成如下两种转化:

  • 总是能成功的类型转化,编译器能在编译时判断出这类转换总是能成功。比如向上转换(upcasting —— 将一个对象引用转化为自己的一个父类或者祖先类类型) 或者在给字面值常亮添加类型注释(比如, 1 as Float)。

  • 强制类型转化,此类转换 Swift 编译器不能确保其绝对成功,如果不成功就引发运行时异常。比如乡下转换(downcasting —— 将一个对象引用转化为其某个子孙类类型)。

Swift 1.2 把这两中操作分割开来,变成了两个独立的运算符。总是能成功的转化还是使用 as 运算符,二强制转化则使用新的 as! 运算符(注意这里不是两个运算符叠加在一起,它就是一个运算符)。 ! 暗示此类型转化可能会失败。这样,你一眼扫过代码就能知道那个类型转化会引发程序奔溃。

如下示例展示了这个新的语言变更:

class Animal {}
class Dog: Animal {}

let a: Animal = Dog()
a as Dog                // now raises the error:  "'Animal is not convertible to 'Dog';
                        // ... did you mean to use 'as!' to force downcast?"

a as! Dog               // forced downcast is allowed

let d = Dog()
d as Animal             // upcast succeeds

注意区分作为表达式后缀运算符的 !? 以及转换运算符 as!as?

译者注,用于类型注释时(type annotation):

  • 后缀运算符 ! 表示要强制拆箱可为空类型 (forced unwrapping)

  • 后缀运算符 ? 可为空类型的级联访问(optional chaining)

在声明可为空类型时:

  • ! 类型后缀声明一个隐式拆箱的可为空类型(implicitly unwrapped optional)

  • ? 类型后缀声明一个普通的可为空类型(optional)

class Animal {}

class Cat: Animal {}

class Dog: Animal {
  var name = "Spot"
}

let dog: Dog? = nil
dog?.name               // evaluates to nil
dog!.name               // triggers a runtime error

let animal: Animal = Cat()
animal as? Dog  // evaluates to nil
animal as! Dog  // triggers a runtime error

您可以简单记忆为:在 Swift 中 ! 暗示 可能会失败? 暗示 可能为空 nil

MY SUMMARIES OF WWDC SESSION VIDEOS

There has been hundreds of WWDC session videos on Apple WWDC, which provide first-hand knowledges about iOS development from Apple’s engineers’ perspective.

Here records progressively my summaries after watching, mainly about the order and prerequisites of watching parts of them.

For those who are new to it, I highly recommend the ASCIIwwdc website.

Searchable full-text transcripts of WWDC sessions

Find the content you’re looking for, without scrubbing through videos

  • View

    1. ◉ - Introducing Collection View (2012)
    2. ◎ - Advanced Collection Views and Building Custom Layouts (2012)
  • View Controllers

    1. ◑ - Custom Transitions Using View Controllers (2013)
    2. ◑ - View Controller Advancements for iOS 8 (2014)
    3. ◑ - Building Adaptive Apps with UIKit (2014)
    4. ◑ - Bkuilding Interruptible and Responsive Interactions (2014)
    5. ◉ - A Look Inside Presentation Controllers (2014)
  • Transitions

    1. ◎ - Best Practices for Cocoa Animation (2013)
    2. ◑ - Custom Transitions Using View Controllers (2013)
    3. ◑ - Building Adaptive Apps with UIKit (2014)
    4. ◎ - Advanced Techniques with UIKit Dynamics (2013)
  • Dynamics

    1. ◎ - Getting Started with UIKit Dynamics (2013)
    2. ◎ - Advanced Techniques with UIKit Dynamics (2013)
    3. ◎ - Creating Custom iOS User Interface (2014)
    4. ◎ - What’ New in UIKit Dynamics and Visual Effects (2015)
  • Auto-Layout

    1. ◉ - Introduction to Auto Layout for iOS and OS X (2012)
    2. ◎ - Best Practices for Mastering Auto Layout (2012)
    3. ◎ - Auto Layout by Examples (2012)
    4. ◎ - The Evolution of View Controllers on iOS (2012)
    5. ◎ - Taking Control of Auto Layout in Xcode 5 (2012)
  • Networking

    1. ◑ - Networking Best Practices (2012)
  • Objective-C

  • Swift

    see Swift Resources Page

    1. ◎ - Introduction to Swift (2014)
    2. ◎ - Intermediate Swift (2014)
    3. ◎ - Advanced Swift (2014)
    4. ◎ - Swift Playgrounds (2014)
    5. ◎ - Integrating Swift with Objective-C (2014)
    6. ◎ - Swift Interoperability In Depth (2014)
    7. ◎ - Introduction to LLDB and the Swift REPL (2014)
    8. ◎ - Advanced Swift Debugging in LLDB (2014)
    9. ◎ - What’s New in Swift (2015)
  • Text & Font

  • The Developing Tools

    1. ◎ - Xcode Core Concepts (2013)
    2. ◎ - Testing in Xcode 6 (2014)
  • Other

    1. ◎ - Protecting Secrets with the Keychain (2013)
    2. ◉ - Keychain and Authentication With Touch ID (2014)

Swift 官博文章翻译 - 可为空性和 Objective-C

原文链接:Nullability and Objective-C

译者:Mudox

Swift 语言的一个很棒的特性就是它能透明的和 Objective-C 代码互操作,不管是系统提供 Objective-C 框架还是那些你自己写的代码都能。然而,在 Swift 中,可为空的值与不可为空的值引用之间使用明显区别的。比如说 NSViewNSView? 在 Swift 中是两个截然不同的类型,但在 Objective-C 中他们都用 NSView * 表示。由于 Swift 无法判断 NSView * 到底是可为空的引用还是不可为空的引用,所以 Swift 把此类型转换为一个隐式拆箱的可为空类型(implicitly unwrapped optional)—— NSView!

在此前的 Xcode 版本中,Apple 公司对一些框架做了特殊处理,以让它们在 Swift 被转换为适当的可为空类型。Xcode 6.3 引入了一个新的 Objective-C 特性:可为空性注释(nullability annotation),是的程序也能对自己的代码做出同样的处理。

核心关键字: _Nullable_Nonnull

这项新特性的核心就是两个关键字:_Nullable_Nonnull。正如你所想的那样,所有 _Nullable 指针可以为 NULL 或者 nil,而所有 _Nonnull 指针不行。如果你违反了此规则,编译器将会发出警告。

@interface AAPLList : NSObject <NSCoding, NSCopying>
// ...
- (AAPLListItem * _Nullable)itemWithName:(NSString * _Nonnull)name;
@property (copy, readonly) NSArray * _Nonnull allItems;
// ...
@end

// --------------

[self.list itemWithName:nil]; // warning!

在您的 Objective-C 代码中,您几乎可以在任何可以用到 const 关键字的地方使用 _Nullable_Nonnull,当然必须是修饰指针类型。Swift 还未常用的场景提供了更加漂亮的注释方式:对于那些简单的对象类型或者块类型的类成员声明,您可以使用 _Nullable_Nonnull 非下划线版本来就注释他们。

- (nullable AAPLListItem *)itemWithName:(nonnull NSString *)name;
- (NSInteger)indexOfItem:(nonnull AAPLListItem *)item;

对于属性,您也可以使用非下划线的版本,这次不是放在属性名前面,而是把他们挪到属性列表中(括号里面)。

@property (copy, nullable) NSString *name;
@property (copy, readonly, nonnull) NSArray *allItems;

非下划线的版本看起来更加舒服,但是您任然需要把他们加到所有需要的头文件中。您可以使用监控区域(audited region)来简化这个过程,并让头文件变得更加干净。

监控区域(andited region)

为了简化新注释关键字的使用,您可以把您的 Objective-C 头文件中的某段代码标记为 对可为空性进行监控。在此代码段中,所有的简单指针类型都被编译器默认认为是不可能为空的,也就是 _Nonnull。这就大大减少了我们早前的示例中需要做的变动。

NS_ASSUME_NONNULL_BEGIN
@interface AAPLList : NSObject <NSCoding, NSCopying>
// ...
- (nullable AAPLListItem *)itemWithName:(NSString *)name;
- (NSInteger)indexOfItem:(AAPLListItem *)item;

@property (copy, nullable) NSString *name;
@property (copy, readonly) NSArray *allItems;
// ...
@end
NS_ASSUME_NONNULL_END

// --------------

self.list.name = nil;   // okay

AAPLListItem *matchingItem = [self.list itemWithName:nil];  // warning

处于安全性的考量,该规则有如下例外情况:

  • typedef 类型别名语句,根据上下文,本身就是有确定的可为空性。它不受监控区域假设的影响。也就是说在监控区域内,typedef 语句定义的指针类型并不是默认为 nonnull 的,而是取决于定义它的原始类型。

  • 复杂的指针类型必须明确的注释可为空性,不能省略。比如声明一个不可为空的指针只想一个可为空的对象的引用,必须用 _Nullable id * _Nonnull 来声明。

  • NSError 是一个特殊的类型,它被用来通过参数返回错误。它总是一个指向一个可为空 NSError 对象指针的可为空指针,即 _Nullable NSError * _Nullable

兼容性

那么如果您已经有了自己的 Objective-C 框架,现在要混合使用些类型安全么?当然,答案是肯定的。

  • 现存的,已经编译好的 Objective-C 框架代码依然会继续工作,他们的应用二进制接口(ABI)并没有变(其实变化只发生在编译时)。这样意味着,老代码不会扑捉到错误的 nil 赋值。

  • 当你转而使用新的 Swift 编译时,它能对您的使用旧框架代码的当前代码中不安全的行为发出警报。

  • nonnull 不会影响编译器优化。如果为了向后兼容,您仍然可以对您可以在代码中加入检查指针是否为空的逻辑。

大体上您可以把 nonnullnullable 当做断言或者异常捕捉特性来使用:违反协议是程序员本身的错误。毕竟是由您完全控制您的函数会返回什么值,因此在不该返回 nil 的函数中,您应该负责确保它不会返回空值,除非是为了向后兼容。

回到 Swift

现在我们已经在我们的 Objective-C 一端用上了可为空性注释,让我们看看 Swift 一端该跟着怎么变:

在用到注释之前:

class AAPLList : NSObject, NSCoding, NSCopying {
  // ...
  func itemWithName(name: String!) -> AAPLListItem!
  func indexOfItem(item: AAPLListItem!) -> Int

  @NSCopying var name: String! { get set }
  @NSCopying var allItems: [AnyObject]! { get }
  // ...
}

Objective-C 一端添加了注释之后:

class AAPLList : NSObject, NSCoding, NSCopying {
  // ...
  func itemWithName(name: String) -> AAPLListItem?
  func indexOfItem(item: AAPLListItem) -> Int

  @NSCopying var name: String? { get set }
  @NSCopying var allItems: [AnyObject] { get }
  // ...
}

是不是比以前清爽了?虽然只是细微的变化(少了几个类型后缀 !),但是这必将使您在 Swift 中使用以前的框架的心情更加愉快。

详情请参考 Xcode 6.3 Release Notes

iOS NOTES - MEDIA FRAMEWORKS

iOS Media Frameworks Stack

iOS media frameworks Stack

The Trunk Relation Graph

iOS media framework trunk relation graph

Swift 官博文章翻译 - 通过减少动态调度来拉升程序性能

原文链接:Increasing Performance by Reducing Dynamic Dispatch

译者:Mudox

和其他很多语言一样,Swift 运行程序员改写从父类集成来的方法和属性。这意味着程序得在运行时也只用在运行时才能判断所引用的具体的方法或属性,并间接的调用或访问他们。这一技术名为“动态分配 dynamic dispatch”,通过为每次间接调用或访问增加常亮时间的开销来换取语言表达能力的提升。对于性能苛刻的代码,这类开销是不可取的。本文将展示三种通过消除此类动态性来拉升程序性能的方法:finalprivate 以及整模块优化策略。

请看如下代码:

class ParticleModel {
  var point = ( 0.0, 0.0 )
  var velocity = 100.0

  func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
    point = newPoint
    velocity = newVelocity
  }

  func update(newP: (Double, Double), newV: Double) {
    updatePoint(newP, newVelocity: newV)
  }
}

var p = ParticleModel()
for i in stride(from: 0.0, through: 360, by: 1.0) {
  p.update((i * sin(i), i), newV:i*1000)
}

编译器将会生成如下动态分派代码:

  1. 调用 updatep
  2. 调用 updatePointp
  3. 访问 ppoint 元祖属性。
  4. 访问 pvelocity 属性。

这也许并不是你想要的。动态调度在这里之所以必要,是因为 ParticleModel 的子类可能重写其属性。

在 Swift 中,动态调度通过从函数表中搜索正确的函数并间接调用他们来实现。这显然比直接调用来的慢。此外,间接调用还会阻碍很多编译器对代码的优化,这又进一步增加了程序运行的开销。在性能关键的代码中,Swift 提供了一些技术来关闭某些不必要的动态调度以拉升程序性能。

当你确定某个声明不会被覆盖时,使用 final 关键字

关键字 final 可以修饰类,方法或者属性的声明,它指示编译器这些声明不会被后续代码覆盖。这样编译器就能放心的在这些对象上关闭动态调度特性(不生成动态调度的代码)。比如下面的类属性 pointvelocity 和函数 updatePoint() 将被直接访问和调用。而方法 update() 仍然需要通过动态调度来间接的被调用,它也因此能被子类们覆盖。

class ParticleModel {
  final var point = ( x: 0.0, y: 0.0 )
  final var velocity = 100.0

  final func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
    point = newPoint
    velocity = newVelocity
  }

  func update(newP: (Double, Double), newV: Double) {
    updatePoint(newP, newVelocity: newV)
  }
}

It is possible to mark an entire class as final by attaching the attribute to the class itself. This forbids subclassing the class, implying that all functions and properties of the class are final as well.

您可以用 final 修饰整个类的声明,这样做将直接禁止对该类的子类化,因此对其所有属性和方法的访问将都是直接的。

final class ParticleModel {
  var point = ( x: 0.0, y: 0.0 )
  var velocity = 100.0
  // ...
}

private 声明自动推导 final 语义

private 修饰的声明其可见性会限制在声明它的文件里。如果在该文件里,没有发现对该声明的覆盖,编译器就不会为该声明生成动态调度代码,而是直接的访问他们。

假设在该文件中,没有对类 ParticleModel 的覆盖,那么编译器就会关闭对其所有 private 成员的动态调度,取而代之以更加快速的直接访问。 Assuming there is no class overriding ParticleModel in the current file, the compiler can replace all dynamically dispatched calls to private declarations with direct calls.

class ParticleModel {
  private var point = ( x: 0.0, y: 0.0 )
  private var velocity = 100.0

  private func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
    point = newPoint
    velocity = newVelocity
  }

  func update(newP: (Double, Double), newV: Double) {
    updatePoint(newP, newVelocity: newV)
  }
}

上述代码中,pointvelocityupdatePoint() 将被直接访问和调用。由于 update() 没有被 private 修饰,它仍然需要被动态调度。

final 一样,private 也可以被用来直接修饰整个类声明,这相当于在该类的所有成员声明面前加了 private 关键字。

private class ParticleModel {
  var point = ( x: 0.0, y: 0.0 )
  var velocity = 100.0
  // ...
}

通过模块级的优化来对 internal 声明推导出 final 语义

在 Swift 中,所有声明的可见性默认为 internal,也就是说他们只能在定义他们的模块内可见。编译器通常会单独的编译模块内的每个文件,因此它在变异某一个源文件时,无法判断在同意模块内的其他源文件里是否对该源文件内定义的 internal 声明的覆盖。但是如果我们启用了编译器的 Whole Module Optimization 模块级优选项,所以的文件将在一次编译过程中全部被编译。这样编译器就能在整个模块范围类分析是否某个 internal 声明被覆盖了,从而推导出 final 语义以关闭动态调度特性。

让我们回到最开始的代码,这回我们额外添加一些 public 关键到 ParticleModel 的声明中。

public class ParticleModel {
  var point = ( x: 0.0, y: 0.0 )
  var velocity = 100.0

  func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
    point = newPoint
    velocity = newVelocity
  }

  public func update(newP: (Double, Double), newV: Double) {
    updatePoint(newP, newVelocity: newV)
  }
}

var p = ParticleModel()
for i in stride(from: 0.0, through: times, by: 1.0) {
  p.update((i * sin(i), i), newV:i*1000)
}

当开启了模块级优化选项的编译器处理以上代码时,它能够推导出 point, velocityupdatePoint() 方法可以关闭动态调度特性。与此相反,由于 update()public 修饰,其可见性延伸到了模块之外,所以编译器无法断定它具有 final 语义。

Swift 官博文章翻译 - 内存安全:确保值在使用前先初始化

原文链接:Memory Safety: Ensuring Values are Initialized Before Use

译者:Mudox

我们设计 Swift 这门语言时的一个重要的发力方向就是改进编程模型的内存安全性。内存安全有很多方面,本文将由浅入深,先从一个简单的问题开始:如果确保值在使用前被初始化。

Swift 的方式

如果每当一个变量第一次被访问时,该变量都有一个有效的初始值,那么该变量就被认为是“安全”的。不同的语言采用了不同的方式来提供这种安全性。比如 C 语言,它将责任完全交给程序员——这种方法强大,但是也很有难度。C++ 和 Objective-C 通过施加一些强制性的模式来改善此类情况,还有一些语言则(比较极端的)要求变量在定义时就必须初始化。

Swift 采用的主要技术是通过其先进的编译器来对代码的数据流进行分析。由编译器在编译时确保变量在使用前正确初始化,这是是一种名为 明确初始化——Definitive Initialization 的策略。还有很多语言比如 Java,C# 都采用了类似的策略,而 Swift 则是的该策略的一个扩展版本应用于更大范围的变量上面。

本地变量的明确初始化

在 Swift 中有很多场景都用到了该策略,其中最简单的场景就是用于本地变量。相较于“隐式的默认值初始化 implicit default initialization”,明确初始化初始化提供了更大的灵活性,因为它运行你写出如下的代码:

var myInstance : MyClass  // Uninitialized non-nullable class reference

if x > 42 {
  myInstance = MyClass(intValue: 13)
} else {
  myInstance = MyClass(floatValue: 92.3)
}

// Okay because myInstance is initialized on all paths
myInstance.printIt()

这里编译器能分析出 if 语言的两个分支里都对变量 myInstance 做了初始化,因此它确信后面的 printIt() 方法不会被调用于未初始化的内存上面。

明确初始化策非常强大,但是它只有在代码可靠并可预测的情况下才能发挥作用。当你的代码的控制流逻辑比较复杂时,它就可能出意外。比如如下代码:

var myInstance : MyClass

if x > 10 {
  myInstance = MyClass(intValue: 13)
}
// ...
if x > 42 {
  myInstance.printIt()
}

上述代码运行时,编译器会发出警告:“变量 myInstance 在使用前未初始化”。这是因为编译器并不能分析出上下两个 if 语句的条件之间的内在逻辑关系。尽管我们能让编译器照顾到此类个别特殊情况,但是它还是不可能覆盖所有的特殊情况(这其实就是所谓的“停机问题 halting problem”),因此我们决定保持编译规则简单可预测。

Swift 使初始化一个变量变得极其简单。事实上用 Swift 在声明时给出初始化值 var x = 0 比声明一个未初始化的变量 var x: Int 所得到的代码更简短。Swift 提倡在任何可能的时候给声明的变量一个明确的初始化值。还有更加强大的方法就是通过调用 init() 方法来初始化一个变量。想要了解更加详细的信息,请参阅 Swfit Programming Language 的“初始化 Initialization” 一章。

其他的方式

除了明确初始化之外,Swift 在特定情况下也会采用一些其他的策略。您很可能已经在其他语言中碰到过这些策略,因此我们将在本文中简短的介绍下他们。他们都用各自不足之处,所以 Swift 并没有将他们当做主要策略来使用。

将安全性交给程序员:鉴于 C 的普及程度,我们有必要了解下简单的将安全性责任交给程序员这种做法的利与弊。在 C 中使用未经初始化的值会导致不确定的行为 undefined behavior,经常表现为程序的运行时异常。C 语言依赖程序永远都不要犯错误。我们设计 Swift 语言的初衷之一就是让它从本质上就是安全的,所以这一策略果断被我们排除于绝大部分情况之外。但是,Swift 还是提供了诸如 UnsafePointer 这样的 API,以允许你再绝对必要的情况下启用这种策略。

隐式的默认值初始化:可以让编译器隐式的初始化一个值,以确保其安全性。比如,在 Objective-C 中,给实例的成员变量设置一个初始的“零值”,或者像 C++ 那样给类提供默认的初始化器。我们曾深入探索过这一方法,但做种决定不广泛使用它。因为:

  • 它对与那些没有合理初始化值的类型不起作用,比如 protocol 对象并没有 init() 方法可以调用,已经在 Swift 非常普遍的不可为空的类引用。

  • 就算是对于基本类型,比如对于一个 integer 变量,0 常常在上下文中是一个不合理的值。这也是为什么在 Swift 中给变量赋初始化值如此容易的原因之一。此外,这让代码对于后续的维护者更加的清晰明了。

注意:对于 OptionalImplicitlyUnwrappedOptional 这类可以为空的值,把他们默认初始化为空 nil 是理所当然的。因此在 Swift 中所有飞空值都会被自动初始化为空值。

强制在定义时初始化:强制要求程序在定义变量是给与其初始值,意味着 var x: Int 将是非法的,因为它没有提供初始值给编译器。尽管该策略通用于函数式编程语言中, 但是我们认为这一要求国语严格而没有必要,也妨碍了程序员对自然模式的表达。

iOS NOTES - AMAP API DEPICTED

AMap (高德地图) APIs depicted in several graphs I draw.

AMap Searching API

AMap Searching API Graph

iOS NOTES - LOCATION BASED SERVIES

Quick steps to use iOS’s LBS technology.

Core Location

iOS devices integrates various hardware components, such as:

  • GPS (Global Positioning System) for positioning

  • Hardware compass for heading monitoring.

  • WiFi for positioning.

  • Cellular network for cell-tower triangulation.

  • Blue tooth for iBeacon ranging.

  • some data sensors for improve positioning accuracy under some circumstances.

to provides users with following LBS abilities as much as possible:

  1. Location Updates

    1. Standard location updates

    2. Significant location updates

  2. Heading monitoring

  3. Region monitoring

  4. iBeacon ranging

  5. Visit events

The CLLocationManager acts just like an NSNotificationCenter (but it is not a singleton) between the LBS hardwares and your App, you use it to request the authorization for LBS functionalities you are planning to use afterwords, and adjusts the relevant parameters of them before starting their notification updating loops.

After you call one of its’ start*** or request*** methods to emit requests for one of the 5 LBS abilities mentioned above, the CLLocationManager activate relevant hardware components, when the data is available it notifies you asynchronously by calling one of the its’ delegate’s methods.

Core Location Map

Work flow of using LBS abilities.

  1. Project setup

    1. Enable Background Location Updates Background Mode capability.

    2. Add NSLocationAlwaysUsageDescriptions or NSLocationWhenInUseUsageDescription key to info.plist.

  2. Configuring CLLocationManager

    1. Creating a CllocationManager instance and hold a strong reference to it.

    2. Specify location manager’s delegate, usually be a view controller.

    3. Check & request authorization status.

    4. Configures the relevant properties for the LBS functionality you are about to use.

    5. Before starting each LBS updating functions, there are also corresponding APIs you can invoke to check the services availability.

    6. Call start** methods to start the various LBS notification loops.

    // declare as some long-standing reference outside of function body.
    let locationManager = CLLocationManager()
    --------------------
    // within functions ( be it in viewDidLoad() )
    // designate delegate
    locationManager.delegate = self
    // request for authorization
    locationManager.requestAlwaysAuthorization()
    // configure updating related settings
    locationManager.activityType = .AutomotiveNavigation
    locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
    locationManager.distanceFilter = 10
    // finally check device & service availability before starting notification loop.
    if CLLocationManager.locationServicesEnabled() {
      locationManager.startUpdatingLocation()
    } else {
      let alert = UIAlertController(
        title: "Service Not Available",
        message: "The location is not available or has been shut down.",
        preferredStyle: .Alert)
      presentViewController(alert, animated: true, completion: nil)
    }
    
  3. Implement CLLocationManagerDelegate methods in you designated delegate object to:

    • handle received location data updates.

    • handle LBS failures.

    • handle authorization status changes.

MapKit

In general, MapKit:

  1. shows map in one of three map types:

    • Standard

    • Satellite

    • Hybrid

  2. along with many built-in elements:

    • compass

    • POIs (points of interest)

  3. and provides developer with two kinds of customizable presentation facilities:

    • annotations

    • overlays

As of managing annotations, MapKit adopts the same design pattern as that is heavily used by UITableView – decoupling data model from presentation tools through reuse pool. Hence, there comes separate class hierarchies for storing annotation (overlay) data, and presenting them respectively.

  • data object

    • all objects that conforms to MKAnnotation protocol, are responsible for storing data for annotations, such as location, textual info, etc.

    • all objects that conforms to MKOverlay protocol, are responsible for storing data for overlays, such as location, etc.

  • presentation tools

    • instances that inherit from MKAnnotationView can be reused to display a data objects.

    • instances that inherit from MKOverlayRenderer can be used to display a overlay objects.

MapKit map

Customize annotation view

A annotation view usually consist of 2 parts:

  1. The view view.

Set its’ image property to change its’ appearance.

  1. The callout view, which is popped up when the pin view is selected.

The built-in callout view is not exposed for customization, so we should disable the canShowCallout property

SWIFT NOTES - CLOSURE

Thanks to the host of technologies provided by the Swift compiler, the closure comes with a bunch of syntactic sugars that could sweet you to diabetes.

The full syntax of a closure:

{
  (parameters) -> retrunType in
  ... statements ...
}

Here is an example that uses the array’s method sorted to sort an array of word.

var words = [ "Dolor", "eum", "id", "suscipit", "necessitatibus", "quod", "hic", "dignissimos" ]

let sortedWords = words.sorted({
  (lhs: String, rhs: String) -> Bool in
  return lhs < rhs
})

As the sugars introduced in one by one, we will cut the lines above into an incredibly one-liner.

Sugar #0 – trailing closure

Often, closure parameter is placed last in parameter list. Swift thus provides trailing closure, which means your can write the inline closure just outside the parameter list, following the closing ).

Furthermore, if the closure is the only parameter, then the parenthesis can be omitted.

// trailing closure
let sortedWords = words.sorted/*()*/ {
  (lhs: String, rhs: String) -> Bool in
  return lhs < rhs
}

Sugar #1 – return type inference

return type can be inferred by swift compiler.

// omit return type
let sortedWords = words.sorted {
  (lhs: String, rhs: String) /*-> Bool*/ in
  return lhs < rhs
}

Sugar #2 – parameter type inference

parameter types can be inferred by swift compiler as well.

// omit parameter types
let sortedWords = words.sorted {
  (lhs/*: String*/, rhs/*: String*/) /*-> Bool*/ in
  return lhs < rhs
}

Sugar #3 – parenthesis-less

Since no type annotation is needed, the parenthesis can be omitted.

// omit parenthesis
let sortedWords = words.sorted {
  /*(*/lhs/*: String*/, rhs/*: String)*/ /*-> Bool*/ in
  return lhs < rhs
}

Sugar #4 – auto return for single expression closure

If the closure has one statement, then the return statement can also be inferred.

// omit 'return'
let sortedWords = words.sorted {
  /*(*/lhs/*: String*/, rhs/*: String)*/ /*-> Bool*/ in
  /*return*/ lhs < rhs
}

//then we got:
let sortedWords = words.sorted { lhs, rhs in lhs < rhs }

Sugar #5 – shorthand parameter name

Swift provides shorthand parameter names: $0 for the 1st parameter, $1 for the 2nd parameter, and so on. And as an side effect, the whole (parameters) -> returType in statement can be completely omitted

// use shorthand parameters, omit the whole 'in' statement
let sortedWords = words.sorted {
  /*(lhs: String, rhs: String) -> Bool in*/
  /*return*/ $0 < $1
}

// then we got:
let sortedWords = words.sorted { $0 < $1 }

Sugar #6 – operator as a closure

In swift, operator is a function, which in turn is a special closure, so…

// comes operator!
let sortedWords = words.sorted(<)

SOME UNICODE CONCEPTS CLARIFIED

Collect several Unicode concepts encountered when I learn Swift’s String type.

  • UCS

    Universal Coded Character Set (通用字符集)

    The Universal Coded Character Set (UCS), defined by the International Standard ISO/IEC 10646, Information technology — Universal Coded Character Set (UCS) (plus amendments to that standard), is a standard set of characters upon which many character encodings are based. The UCS contains nearly one hundred thousand abstract characters, each identified by an unambiguous name and an integer number called its code point.

  • Unicode

    统一码,万国码, 单一码

    Unicode is a computing industry standard for the consistent encoding, representation, and handling of text expressed in most of the world’s writing systems. Developed in conjunction with the Universal Character Set standard and published as The Unicode Standard, the latest version of Unicode contains a repertoire of more than 110,000 characters covering 100 scripts and multiple symbol sets.

    As for its’ code space layout:

    Unicode comprises 1,114,112 code points in the range 0x0 to 0x10FFFF. The Unicode code space is divided into 17 planes (the basic multilingual plane, and 16 supplementary planes), each with 65,536 (= 216) code points. Thus the total size of the Unicode code space is 17 × 65,536 = 1,114,112.

  • UTF

    UCS/Unicode Transformation Format (通用字符集转换格式, Unicode 转换格式)

  • UTF-8

    UTF-8 (U from Universal Character Set + Transformation Format—8-bit[1]) is a character encoding capable of encoding all possible characters (called code points) in Unicode. The encoding is variable-length and uses 8-bit code units. It was designed for backward compatibility with ASCII and to avoid the complications of endianness and byte order marks in UTF-16 and UTF-32.

  • code point (code position)

    In character encoding terminology, a code point or code position is any of the numerical values that make up the code space.

  • Unicode scalar

    Behind the scenes, Swift’s native String type is built from Unicode scalar values. A Unicode scalar is a unique 21-bit number for a character or modifier.

    The distinction between Unicode scalar & Unicode code point could be clarified as follows:

    A Unicode scalar is any Unicode code point in the range U+0000 to U+D7FF inclusive or U+E000 to U+10FFFF inclusive. Unicode scalars do not include the Unicode surrogate pair code points, which are the code points in the range U+D800 to U+DFFF inclusive.

    It is a Swift language specific notion, or more actually, a Swift defined internal type for storing string charactor’s Unicode points that Swift choose to support. Behind the scene, it’s a 21bit long numeric type, but not all number in the range can reponds to a valid Unicode point.

    So mathematically, the Unicode points universal set is a discrete subset of integer set [0, 0x10FFFF]. The Swift Unicode scalar universal set is, in turn, a discrete subset of Unicode code point universal set (with all surroagte pair code points stripped).

  • code unit

    A code unit is a bit sequence used to encode each character of a repertoire. Encodings associate their meaning with either a single code unit value or a sequence of code units as one value.

  • extended grapheme cluster

    Every instance of Swift’s Character type represents a single extended grapheme cluster. An extended grapheme cluster is a sequence of one or more Unicode scalars that (when combined) produce a single human-readable character.

SWIFT NOTES - FUNCTIONS

Excerpts from the “Functions” section of the official docuemnt 《The Swift Programming Language》

Function Parameters

Parameter names

A parameter name can have a internal name and an external name declared in the form of: external_name internal_name: type.

Explicitly specify an external name for the first parameter to enable it when calling.

func join(aString lhs: String, toString rhs: String) -> String {
  return lhs + rhs
}

println(join(aString: "Hello", toString: " World!"))

Swift compiler automatically generates external name from corresponding internal names of all parameters except the 1st parameter.

Use _ to suppress auto-generating external name: _ internal_name: type

func join(_ aString: String, _ toString: String) -> String {
  return aString + toString
}

println(join("Hello", " World!"))

Parameters with default value

Parameters with default value of the form [external_name/_] internal_name: type = default_value are better be placed at end of the parameter list.

func Foo(arg1: String, arg2: Int = 30, _ arg3: Bool) {
  ...
}

Foo("text", arg2: 1, true)

Variadic parameters

Declare variadic parameter in form name: type..., which, in the function body, is of type [type].

Only one variadic parameter is allowed in a parameter list.

Variable parameters

Prefix parameter names with keyword var to make them modifiable inside the function body.

It is just another small syntactic sugar brought by Swift, the change made in the function body will not propagate outside the function body.

In-Out parameters

Prefix parameters names with keyword inout to propagate the change to the parameter inside function body outside.

When specifying argument for inout parameters, prepend & to the argument name to indicate that it could be modified during the function call.

In-out parameters

  • cannot have default values
  • cannot be variadic parameter
  • implies var, so cannot be marked as var or let
func swapTwoInts(inout a: Int, inout b: Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

var a = 2
var b = 10
swapTwoInts(&a, &b)
println("after swapping, a = \(a), b = \(b)")

Function Return Values

Functions without a defined return type return a special value of type Void. This is simply an empty tuple, in effect a tuple with zero elements, which can be written as ().

You can use a tuple type (or a optional tuple) as the return type for a function to return multiple values as part of one compound return value.

// wrap multiple return values in an optional tuple.
func minMax(array: [Int]) -> (min: Int, max: Int)? {
  return (1, 3) // no need to specify tuple element names again
}

if let minMax = minMax([1,2,3]) {
  // use name to fetch tuple element.
  println("min: \(minMax.min)\tmax: \(minMax.max)")

  // use index to fetch tuple elements.
  println("min: \(minMax.0)\tmax: \(minMax.1)")
}

Function Types

A function type is made up of its’ parameter types and return type.

In Swift, function is first class object, so feel free to use them as other normal objects:

  • declare constants or variables to hold them, and call them latter.

  • passing them as arguments into functions.

  • return them from functions.

  • declare theme as type alias for convenience.

  • even nest them in another function.

// declare a type alias for long function types
typealias cmp = (Int, Int) -> Bool

func whichCmp(functionPassedIn: ()-> Bool) -> cmp {
  // nested fucntion definition
  func Foo(lhs: Int, rhs: Int) -> Bool {
    return false
  }

  func Hoo(lhs: Int, rhs: Int) -> Bool {
    return true
  }

  // function being returned
  return functionPassedIn() ? Foo : Hoo
}

func aFunc() -> Bool {
  return false
}

// function being passed in as an argument
whichCmp(aFunc)(1334, 234)

iOS NOTES - CASTING

Collect all my gain from study & using Swift’s casting mechanism here.

First defining a sample class hierarchy:

class SuperClass {
  func say() {
    println("super class")
  }
}

class Subclass: SuperClass {
  override func say() {
    println("subclass")
  }
}

3 Kinds of Castings

  1. Natural Casting

    Used in up-casting (i.e. casting from a sub-class instance to a super class instance)

    var a = SubClass()
    var b = a as SuperClass
    
  2. Unconditional Casting (or forced casting)

    Used in down-casting (i.e. the contrary of the above).

    When the casting failed, it would incur a panic.

    Use it when you are confident about the down-casting.

  3. Conditional Casting

    Used in down-casting, but it always returns optionals whether succeed or fail, that means when not applicalbe, instead of emitting a panic, it returns nil.

Conclusion:

  • Natural casting is used in always-succeed castings.

  • Conditional & Unconditional castings are used in might-fail castings.

2 Operator for Casting

  1. The is operator

  2. The as operators - as, as?, as!

Special casting scenarios in practice

Protocol Casting

In Swift the relationship between a protocol and the classes adopting that protocol is like the relationship between a super class and its’ sub-classes. Hence casting a protocol object, such as the AnyObject to its’ underlying class is regarded as a down-casting.

import UIKit // import AppKit

let a: AnyObject = "String"
let b: a as! String

There are 3 special types: Any, AnyObject, AnyClass.

By tracing the source code, you would find the following:

/// The protocol to which all classes implicitly conform.
///
/// When used as a concrete type, all known `@objc` methods and
/// properties are available, as implicitly-unwrapped-optional methods
/// and properties respectively, on each instance of `AnyObject`.
@objc procotol AnyObject {}

/// The protocol to which all class types implicitly conform.
///
/// When used as a concrete type, all known `@objc` `class` methods and
/// properties are available, as implicitly-unwrapped-optional methods
/// and properties respectively, on each instance of `AnyClass`.
typealias AnyClass = AnyObject.Type

/// The protocol to which all types implicitly conform
typealias Any = protocol<>

There exists a prerequisite for the rules all above: the Foundation framework must be imported. (Usually, you import UIKit or AppKit, which implicitly import Foundation framework). Only then can swift compiler be able to recognize the @objc keyword, and have Objective-C type bridging ability.

Optional AnyObject Collection Casting

For a optional of Collection of AnyObject that reference objects of the same class (or super class) T, can be [un]conditionally casted to [T] (without being wrapped in optional anymore)

import UIKit // import Appkit

// optional array of String.
let a: [AnyObject]? = ["Newyork", "London", "Peking"]
let b = a as! [String] // succeed.

// optional array of mixed object that have no common super class.
let a: [AnyObject]? = ["Newyork", 1983, 3.14, false]
let b = a as! [String] // fail: not all element are of String.

// optinal array of mixed objects that derived from the same super class.
let a: [AnyObject]? = [Subclass(), SuperClass(), SuperClass(), Subclass()]
let b = a as! [Subclass] // succeed: not all element are of String.

// implicitly unwrapped optional dictionary with String typped keys and Int typed values.
let a: [NSObject: AnyObject]! = ["id1": 32, "id2": 66]
if let b = a as? [String: Int] {
  println(b)
}

In the code list above, the String is a structure type in Swift (no a class type), but it can also be referenced by a AnyObject instance. The rules come from the following excerpt from “Using Swift with Cocoa and Objective-C” official document:

An object is AnyObject compatible if it is an instance of an Objective-C or Swift class, or if the object can be bridged to one.

There exist several swift - Objective-C type bridging depicted as follows:

Siwft - Objective-C Bridging

Hence, back to the code listing above, the Swift type String can be bridged to NSString Foundation class, then it is AnyObject compatible.

In practice, there exists quit a few occasions that you need to cast optional collections to type specific Swift collections to utilize their underlying methods or properties.

For example, when you invoke the Objective-C APIs that return NSArray, NSDictionary, NSSet, you would get [AnyOject]! [NSObject: AnyOject]!, [NSObject]! respectively, you could cast [un]conditionally to a more concrete Swift collection type before you access the individual elements within they.

When you use as! (the unconditional casting), you got an unwrapped collection in one line of code.

let asset: AVURLAsset = ...
for meta in asset.commonMetadata as! [AVMetadataItem] {
  switch meta.commonKey {
  case AVMetadataCommonKeyTitle:
    item.title = meta.stringValue
  case AVMetadataCommonKeyArtist:
    item.artist = meta.stringValue
  case AVMetadataCommonKeyAlbumName:
    item.albumName = meta.stringValue
  case AVMetadataCommonKeyArtwork:
    switch meta.value {
    case let data as NSData:
      item.artwork = UIImage(data: data)
    case let dict as [NSObject: AnyObject]:
      item.artwork = UIImage(data: dict["data"] as! NSData)
    default:
      assert(false, "Invalid metadata value type")
    }
  default:
    break
  }
}

iOS NOTES - KEYBOARD

Handle iOS keyboard poppu & resignment gracefully.

UIWindow provide 6 keyboard related notifications

  • UIKeyboard[Will/Did]ShowNotification

  • UIKeyboard[Will/Did]HideNotification

  • UIKeyboard[Will/Did]ChangeFrameNotification

After playing with these notifications above, I found:

  1. When you want to move obscured contents or views to above the keyboard, put the frame adjustment code in *Will* notifications, because the handler methods seems to be invoked within the same animation block that provides the keyboard revealing animation.

  2. If you are only interested in tracing keyboard’s frame (more specifically the height) during keyboard’s presence, monitoring UIKeyboardWillShowNotification seems enough, no need to monitoring UIKboardWillChangeFrameNotification additionally.

  3. The frame size stored in UIKeyboardFrameBeginUserInfoKey and UIKeyboardFrameEndUserInfoKey keys will only differ after keyboard is first shown and before it is hidden. When the keyboard is first shown or is resigned, the Begin or End frame is equal.

Strategies for move contents above the keyboard:

For contents embedded in UISCrollViews

Way #1 – Adjust the bottom edge inset value of the containing scroll view’s contentsInset property and scroll active view into visible area using scrollRectToVisible: animated: method.

Way #2 – Adjust containing scroll view’s contentSize & contentOffset properties.

No matter which way above you choose, remember to adjust scrollIndicatorInsets’s bottom edge inset value to make the indicator fully un-obscured from the keyboard.

For contents outside any UIScrollView

Recalculate and set its’ frame.origin.y value in UIKeyboardWillShowNotification handler method, and the movement will be animated along with the revealing of keyboard perfectly.

func handleKeyboardNotification(notify: NSNotification) {
  let value = notify.userInfo?[UIKeyboardFrameEndUserInfoKey] as NSValue
  let keyboardHeight = value.CGRectValue().height

  switch notify.name {

  case UIKeyboardWillShowNotification:
    theViewToMove.frame.origin.y = self.view.bounds.height - keyboardHeight - theViewToMoveMargin - theViewToMove.bounds.height
    theScrollViewToAdjust.contentInset.bottom = keyboardHeight
    itemsTable.scrollIndicatorInsets.bottom = keyboardHeight

  case UIKeyboardWillHideNotification:
    theViewToMove.frame.origin.y = self.view.bounds.height - theViewToMoveMargin - theViewToMove.bounds.height
    theScrollViewToAdjust.contentInset.bottom = 0.0
    itemsTable.scrollIndicatorInsets.bottom = 0.0 // the default value

  default:
    assert(false)
  }
}

References:

ENGLISH VOCABULARY - CONFUSION GROUPS

Words groups I collected when expand my vocabulary.

I expand it day by day!

Hew out of the mountain of despair a stone of hope and you can make you life a splendid one!


amnesia, mnemonic
anemia (anaemia), anaemic
anorexia


similar, similarity
simulate, dissimulate ( = dissemble ), imitate, emulate
assimilate, assimilation <-> dissimilate, dissimilation != dissemilate, dissemination
stipulate
stimulate, stimulus, stimulant


imitate
intimate
intimidate == browbeat, bluster, cow, intimidating == intimidatory, intimidator, intimidation


analgesic, analgesia
an(a)esthetic, an(a)esthesia
antibiotic
antibody
antidote
antiseptic, aseptic


absurd
abuse, disabuse
amuse, amusing, amusement
accuse, accusation
accuser <–> defendant, accused


agile, agility
fragile, fragility, crisp, brittle, delicate


anaerobe, anaerobic
anhydrous, dehydrate
anorexia


affable
amiable, amity
amicable


acuity
acumen


accumulate, accumulation
cumulate, cumulus
curdle, coagulate, congeal, clot, gel
commutative


antipathy
animus, animosity
abominate, abomination
averse, aversion


abrogate
abnegate
abstain
abolish
annul
renounce


absolve, absolution
amnesty
acquittal


allege, allegory, allegation
arrogate
aphorism


annex, annexation
adjunct
addendum
accessory (or, accessary)


necessary, necessitous
accessory
accessibility


apex
acme != acne
crest
cusp
climax, anticlimax
peak


alloy
alley
allay
ally, alliance


vow
avow
vowel
bowel


aver
averse, aversion
avert
adverse, adversity
advertise, advertisement


averse
animus, animosity
hostility, hostile <–> hospitality, hospitable
antagonism, antagonise, antagonist


artery, aorta
vein
vessel
vascular
corpuscle
anemia


throat
lung
liver
gallbladder –> bile (or, choler, gall)
stomach
bowel, intestine, small, intestine, large, intestine
bladder
anus


appear, appearance
appeal, appealing
apparent, apparel
appease, appeasing, appeasement


consider, considerable, considerate
appreciate, appreciable
appropriate, appropriateness, appropriation


condiment
salt, pepper, vinegar, sugar


bounteous, courteous
courtesy, courteous


demo
democrat, democracy, demotic != demonic
demagogue
demolish, demolishment


coral
corral
carol
cameo


asthma
anthem, carol
chrysanthemum
chrysalis
talisman


chasm
canyon
canny


precious
appreciate
appreciable, inappreciable
depreciate


contrite, contrition
chondrite


canoe
clue
cliff


boisterous
cloister


comely
comet
comedy
comity
comic


atherosclerosis
arteriosclerosis


contentious
argumentative


deforestation
conflagration


covenant
conversant
countenance


allege, allegation
arrogate, arrogation
arrogant, arrogance
abrogate
derogate, derogatory, derogative
surrogate


axle
axis
axe
axiom, axiomatic
aphorism, aphorize
pith, pithy


ablution
deluge
divulge
dilute, diluted, dilution


eradicate
exterminate
extinguish
massacre
slaughter
carnage
eliminate
obliterate


impetus, impetuous, impetuously, impetuosity
perpetrate, perpetrator
perpetuate, perpetuity


lenient, lenience, leniency
linen, linoleum
liaison
lien


tar -> tarpaulin
flax -> linen -> linoleum


wax -> linoleum
varnish -> wood
glaze -> porcelain


plum, prune
plume, plumage
plummet
plumb, plumber, plumbing


clay
glaze
porcelain


pottery
crockery
ceram, ceramic
earthenware
stoneware
china
porcelain


kelvin
celsius
fahrenheit


spices, spicy
specious
species, subspecies


plateau
highland
mesa
plain, flatland


plate
platen
platelet
plateau
palette


endorse
dorsal
docile


protean
protein
methane
ethane
propane


sport shirts
vest, T-shirt, undershirt
sweater
running shoes, jersey
kneelet, knee cap


bag
portfolio
briefcase
knapsack, hiking bag


surge
resurrect, resurrection == resurgent, resurgence
insurrection, insurrectionist, insurrectionary == insurgent, insurgence, insurgency
rebel, rebellion, rebellious, rebelliousness


surgeon, surgery
burgeon
curmudgeon
pigeon


agile, agility
fragile, fragility, crisp, brittle, delicate


anaerobe, anaerobic
anhydrous, dehydrate
anorexia, anorexic


affable
amiable, amiability
amity <-> enmity
amicable


acuity
acumen


unmeasurable, immeasurable
mensurate, immensurable
commensurat


limber
lumber
grumpy
grumble


squeeze
squal
squelch, squash, quell
mash, smash
mars
pulp
rush, crush
rash, crash
clash
crumb, crumble
rumple, crumple
rumble, grumble
grump, grumpy


kudos judo karate aikido koans

cliche niche attache

ERROR COLLECTION - IOS

Errors that I collected day by day, when developing iOS apps.

  • Specifying an invalid frame size (i.e. 0 width or 0 height), can make UIView’s such as UISlider unresponsive to user interaction.

  • Always wrap multiple statements following a switch case: in a curly brace, where we can even put a variable declaration in it.

  • Should NOT assgin one instance of UIImage to multiple UITextField.leftView or UITextField.rightView properties.

  • UIImageView, by defaults, is NOT userInteractionEnabled, hence sub views under them may not receive touch events.

  • When creating outlets for UILabel views, DO NOT name the property “title”, cause the super class of your view controller UIViewController itself has a property ‘title’, it will incur exception at runtime time.

  • Remember to clean dead connnection recorded by storyboards for controls & views in interface builder window.

  • Dragging an element with key pressed, will copy it’s attributes as well as it’s connections and other info set in the interface builder and uitility panes.

  • When presenting a view controller from a content view controller embeded in a navigation view controller, it is the navigation view controller, rather than the embeded content view controller, which is presenting the view controller, while the replaced view controller is called the source view controller.

  • When customizing table view cells, DOT NOT use UIButton to cover the cell for triggering the segue, which would bring a function redundant and thus complicates things.

  • DO NOT auto-layout a subview within a auto-layout’ed UIScrollView when you plan to perform zooming operation in it.

  • After getting a reused cell, make sure all its’ states get reset to the current value or the default value, otherwise the remained states set by last usage would mess your up.

  • setting clipsToBounds to true will clips layer shadow off.

SETUP MY ARCH LINUX ENVIRONMENT

The marathon of installing & tunning the Arch Linux to my flavor.

SUMMARY

Arch Linux + Awesome WM + xterm, that is the main skeleton of my system.

I settled on this combination under the rule:

  • minimalistic environment, no huge DEs like GNOME, KDE or the likes.

  • fast revolution, always surfing in the front, since it is for personal use, why not …

I choose LightDM, because it

  1. is developed independent of other DEs, hence I don’t have to be forced to install a bunch of GNOME or KDE dependency packages to only for making it run.

  2. is lightweight. Very small package size, therefore starts up pretty fast, as I can see.

  3. has many front ends (a.k.a. greeters) due to it cross-desktop feature.

Among various greeters, I currently use lightdm-gtk3-greeter. It has a simplistic and neat login screen, just the necessary elements I need.

THE WINDOW MANAGER – AWESOME WM

I have tried two ways of starting Awesome WM during system boot.

The first way, is using a display manager, which will presents you a login screen, where you enter your user ID & password. After authentication, it will start the Awesome WM for you.

The second way is to use xinit (and it’s front-end script startx). When display manager is absent in the startup process, system will bring you to one of the tty consoles, which is just a simplistic command line interface, then you type startx manually, which then, according the configuration in ~/.xinitrc, do some initial setting work and finally start the Awesome WM and transfer control to it.

Of the 2 ways I’ve tried, I prefer the first one – using a display manager. Because the display manager:

  • the installation & configuration process is relatively simpler than the xinit way.

  • startup dependent services (e.g. audio, network etc.) in correct order thanks to systemd’s dependency management.

  • fully utilize the systemd’s concurrency startup feature, making the whole startup process pretty faster than the xinit way.

  • run fast, there is no need to login to tty console, and type …, which as I’ve seen, took more time to initiates.

With display manager

Installing LightDM

First, install LightDM & lightdm-gtk3-greeter from official repository. An extra advantage of choosing lightdm-gtk3-greeter is that you do not need to modify the /etc/lightdm/lightdm.conf to let the LightDM back-end use it. It is the reference (default) greeter.

Then register LightDM to systemd, making it get started on boot automatically.

sudo pacman -S lightdm, lightdm-gtk3-greeter

sudo systemctl enable lightdm.service

Configuring LightDM

Without display manager

Without display manager, you should first login into the tty1, then type startx to start the Awesome WM.

Through some configuration, the 2 steps mentioned above can be automated:

Step 1 – automatic login to virtual console

create the following file and its’ parent directory if not exists.

# /etc/systemd/system/getty@tty1.service.d/autologin
------------------------------------------------------------------------------
[Service]
ExecStart=
ExecStart=-/usr/bin/agetty --autologin mudox --noclear %I 38400 linux
Type=idle

Step 2 – start X at login

First install the xorg-xinit package from the Arch Linux official repository, which provides the xinit command & its’ front end – the startx script, besides, it also put a template xinitrc file under /etc/skel/ directory.

Then, base on /etc/skel/.xinitrc, create ~/.xinitrc as follows:

#!/bin/sh
#
# ~/.xinitrc
#
# Executed by startx (run your window manager from here)

if [ -d /etc/X11/xinit/xinitrc.d ]; then
  for f in /etc/X11/xinit/xinitrc.d/*; do
    [ -x "$f" ] && . "$f"
  done
  unset f
fi

xrdb -merge ~/.Xresources # if you have ever created it.

# exec gnome-session
# exec startkde
# exec startxfce4

exec awesome # make sure it's on the last line

Finally, add the following code into you shell login script, such as .profile for bash and .zlogin for zsh.

# ~/.zlogin
------------------------------------------------------------------------------
[[ -z $DISPLAY && $XDG_VTNR -eq 1 ]] && exec startx

references:

MOUSE ACCELERATION

Type xset q | grep Pointer to see current mouse acceleration setting.

Try xset m <acceleration> <threshold> with different values to find the best combination for your feeling.

where acceleration defines how many times faster the cursor will move than the default speed. threshold is the velocity required for acceleration to become effective, usually measured in device units per 10ms. acceleration can be a fraction, so if you want to slow down the mouse you can use 12, 13, 14, … if you want to make it faster you can use 21, 31, 41, …

Threshold defines the point at which acceleration should occur in pixels per 10 ms.

I found my lucky combiantion is 1/4 8 and I add the setting command into rc.lua of Awesome WM to apply the setting on each startup.

references:

INPUT METHOD

The ibus + isbus-rime combinations works nicely on my Arch Linux.

After ibus gets installed, run ibus-setup, it will show a setting guide window where you can adjust ibus settings to adapt to Awesome WM environment.

  • I prefer to change the keyboard shortcut of switching to next input method to <Atl><Shift>space

  • Check off the Embed preedit text in application window option, because I found it does not run properly in some applications (e.g. Vim).

On environments, ibus-daemon can not be loaded automatically on startup, so we need to manually run it. There are many ways to auto-start applications on linux platform, I choose to let Awesome WM to start it by adding auto-start code in rc.lua.

For ibus-rime, it is in tranditional chinese mode by default. To switch to simplified chinese mode, press Ctrl-~ when ibus-rime is active to open setup candiate menu and choose 朙月拼音-简化字

sudo pacman -S ibus ibus-qt ibus-rime

ibus-setup

# manually start ibus daemon for this session.
# this command has been added in my Awesome config file 'rc.lua' to auto-start
# it in the beginning of each Awesome session.
ibus-daemon -drx

references:

WINDOW MANAGER

On Linux platforms, I prefer WMs to DEs.

The Awesome WM is my favorite window manager.

see SETUP MY AWESOME WM ENVIRONMENT for details.

SHELL ENVIRONMENT

I have used several terminal emulators (gnome-terminal, xvrt …), and finally I settled myself on xterm, which I feel it:

  • consume the smallest resource among other terminal emulators.

  • starts up very fast.

  • is much more robust.

  • is the standard shell for the X Window System, which bring a great compatiblity.

As to shells, I become a zsh fan soon after played with it as well as bash & fish shells. the reason is obvious:

  • it is powerfull than bash, whose syntax is completely covered by zsh.

  • it provides more flexibility in configuration than fish shell.

  • there already exist quite a many user contributed resources on the net, e.g:

Pull down dot-files repo

My configuration resource related to termianl emulator & shells are managed in a github repo – dot-files.

cd ~/Git # ~/Git is the place I assemble most of my github repos.
git clone https://github.com/Mudox/dot-files.git

Setup xterm

First, install xterm from Arch Linux’s official repository.

Then, link out the .Xresources file from my dot-files repo. It is the configuration file that hold my xterm settings (colors, cursors, fonts etc.) among other x utility setttings.

sudo pacman -S xterm
cd ~
ln -sf Git/dot-files/Xresources .Xresources

Setup zsh

see SETUP MY ZSH ENVIRONMENTS for details.

SETUP VIRTUALBOX

Installing Virtualbox

First, from the official repository, install virtualbox package, which comes with virtualbox-host-modules.

Then we need to add the basic vboxdrv kernel module to host kernel.

Finally, add my user name to the vboxusers group in order to use USB port in virtual machines.

sudo pacman -S virtualbox

# manually add vboxdrv to host kernel for one time.
sudo modeprobe vboxdrv

# auto-load vboxdrv on every system startup.
sudo echo 'vboxdrv' > /etc/modules-load.d/virtualbox.conf

# add user name in vboxusers group to use USB ports in vitual machines.
sudo gpasswd -a "${USER}" vboxusers

Configuring Virtualbox

  1. Set Host Key Combination to right <winkey> which is consistent with Awesome WM’s keyboads shortcuts, it’s in File->Preference->Input->Virtual Machine of Oracle VM VitualBox Manager window.

  2. Enalbe Bidiretional clipboard, it’s in Devices->Shared Clipboard->Bidirectional of virtual machine window.

references:

VPN

Setup pptpclient

  1. install pptpclient from the official repository of Arch Linux.

  2. use pptpsetup command to register my VPN account, which is just a helper script that will create a readable text file /etc/ppp/peers/<tunnel_name> where you can change the server address manaually using whatever text editor you like. collect the following information in advance:

    • VPN server’s ip address from your VPN provider.

    • user name of your VPN account.

    • user password of your VPN account.

  3. install ppp-mppe (i.e. Microsoft Pointer-to-Pointer Encryption), if the pptpsetup command complains about MPPE module things.

  4. test configuration

    • use pon <tunnel_name> debug dump logfd 2 nodetach to test the configuration. If everything has been configured correctly, the command should not terminate. Ctrl-C to quit it.

    • type ip addr show, and you will see a new device ppp0 is listed in.

  5. connect VPN using sudo pon <tunnel_name>, sudo poff <tunnel_name> to tear down.

# install pptpclient
sudo pacman -S pptpclient

# add you VPN account (i.e. create a new tunnel)
sudo pptpsetup \
  --create <tunnel_name_whatever_you_like> \
  --server <your_VPN_server_ip_address> \
  --username <username_of_you_VPN_account> \
  --password <password_of_you_VPN_account> \
  --encrypt

# install ppp-mppe, if the command above complains about lacking of `MPPE`
# module things. rerun `pptpsetup` command above after installing it.
sudo pacman -S ppp-mppe

# test 1, the command should not terminate if everything is okay.
sudo pon <tunnel_name_above> debug dump logfd 2 nodetach

# test 2, you would see `ppp0` listed in the output.
ip addr show

# finally, connect!
sudo pon <tunnel_name>

Route all traffic through VPN connection

Manually

Use the powerfull ip command to add a route rule into route table.

# make all packages go through interface ppp0
ip route add default dev ppp0

This route rule is only effective during this ppp session. after your tear down the VPN connection by sudo pon <tunnel_name>, it will vanish.

Automatically

Every executable scripts under /etc/ppp/ip-up.d/ will be called when a VPN connection startup. Hence, we can use it to automatically set route rules.

# /etc/ppp/ip-up.d/01-routes.sh
# ----------------------------------------
#!/bin/bash

# This script is called with the following arguments:
# Arg Name
# $1 Interface name
# $2 The tty
# $3 The link speed
# $4 Local IP number
# $5 Peer IP number
# $6 Optional ``ipparam'' value foo

ip route add default via $4
cd /etc/ppp/ip-up.d
echo 'ip route add default via $4' > 01-routes.sh

# the script file need to have `x` permission to be run.
# it's stdin & stderr will be redirected off terminal, so not output will
# be shown when run.
co
sudo chmod +x /etc/ppp/ip-up.d/01-routes.sh

Modify DNS server list

If you found you still can not access some site (e.g. youtube, twitter, etc.) after establishing the VPN connection, then you should insert servername 8.8.8.8 ahead of existing lines in /etc/resolve.conf.

# /etc/resolve.conf
# ----------------------------------------
nameserver 8.8.8.8
nameserver 192.168.0.1

My hacky way

I wrote a script to get around of this:

# ~/.bin/vpn.sh
# ----------------------------------------
#!/bin/sh

tunnel="your configured tunnel name"

if [ "$#" -ne 1 ]; then
  echo "usage: $0 [on|off]"
  exit 1
fi

case "$1" in
  on )
    # connect
    pon ${tunnel} || exit 1

    # here we just overwrite the /etc/resolv.conf by `echo`ing the hard
    # written DNS list to it.
    printf "nameserver 8.8.8.8\nnameserver 192.168.0.1" > /etc/resolv.conf || exit 1
    ;;
  off )
    # disconnect
    poff ${tunnel}

    # some as above, we just `echo` back.
    echo 'nameserver 192.168.0.1' > /etc/resolv.conf || exit 1
    ;;
  * )
    echo "usage: $0 [on|off]"
    ;;
esac

unset tunnel

in your .bashrc or .zshrc file:

alias vpon='sudo ~/.bin/vpn.sh on'
alias vpoff='sudo ~/.bin/vpn.sh off'

then, you can type vpon to turn on the VPN, and vpoff to shutdown.

references:

SETUP MY VIM ENVIRONMENT

It is the Vim that bring we into the marvelous OSS world. Fiddling with it is full of surprise and happy.

Below records my steps of setting up my Vim environment after every system re-installation.

Installing Vim

my vim config have be tested on:

  • Windows XP and above.

  • Mac OSX 10.9 and above using MacVim.

  • Arch Linux.

NOTE: currently I prefer to GUI version than terminal version, hence most of my configurations are tailored to GUI environments.

Setup My Vim-Config Repo

First pull down my vim-config repo from github.

Then create a directory named neobundle under the pulled down repo, which will holds almost all vim plugins that will be synced by neobundle later.

Create the initial cur_mode file under .vim/chameleon/, which always stores the chameleon mode of next vim session.

# On Widnows, Must Be Put In C:/Documents And Settings/<User Name>/Vimfiles
git clone https://github.com/Mudox/vim-config.git ~/.vim

cd .vim
mkdir neobundle

cd chameleon
echo 'all' > cur_mode

Install Prerequisites Vim Plugins

Install vim-chameleon

vim-chameleon is my own plugin for managing massive and ever growing vim & vim plugin configurations.

cd ~/.vim/neobundle
# NOTE: The Renaming Is Important
git clone https://github.com/Mudox/vim-chameleon chameleon

Install neobundle.

neobundle is a sophisticated vim plugin manager that I have been using for a long time.

cd ~/.vim/neobundle
# NOTE: The Renaming Is Important
git clone https://github.com/Shougo/neobundle.vim neobundle

Install & compile vimproc.

vimproc is another plugin written by Shougo that is very useful, and is required by neobundle. The point is that you need to compile it to get a dynamic library after pulling down its’ repo.

cd ~/.vim/neobundle
# NOTE: The Renaming Is Important
git clone https://github.com/Shougo/vimproc.vim vimproc

cd vimproc
make # see vimproc/README.md for compilation commands for various platforms.

Run vim to see all other 140+ plugins get installed.

You can run vim in terminals or open gVim. Better run vim in terminal to watch the plugins installing progress and spot any errors clearly.

Vim Environment For Specific Use Case

Web Developing

Node.js (and NPM which comes with it) is the essentials of everything below.

HTML

JavaScript

I use:

npm install jshint -g
npm install jslint -g
npm install eslint -g
npm install js-beautify -g

CSS

I use:

npm intall csslint -g
npm install csscomb -g

Python Scripting

Lua Scripting

Go Scripting

C/C++ Coding

ERROR COLLECTION - BASH

Errors that I collected day by day, when writing the Bash scripting language.

  • Body of select constructs need a break; to quit the selection loop.
select answer in #choices#; do
  #body#
  break; # <- go out of selection loop.
done
  • Always source before testing a updated command.

  • Whence quoted with ", which is the most case, use the @ form (i.e. "${ARRAY[@]}") to expand a array correctly. The * form will make the expanded string as a single word.

  • The local path is the source of all evil. It will shaddow the global path where binary search paths is hold in zsh.

  • No need to " quote variable that expand to a number in $(( )), which need a real number.

index=$(( RANDOM % "${#array[@]}" )) # no need to double quote '${array[@]}' here

ERROR COLLECTION - BASH

Errors that I collected day by day, when writing the Bash scripting language.

  • Body of select constructs need a break; to quit the selection loop.
select answer in #choices#; do
  #body#
  break; # <- go out of selection loop.
done
  • Always source before testing a updated command.

  • Whence quoted with ", which is the most case, use the @ form (i.e. "${ARRAY[@]}") to expand a array correctly. The * form will make the expanded string as a single word.

ERROR COLLECTION - JAVASCRIPT

Errors that I collected day by day when writing the JavaScript language.

  • when assign a function to a event property, dot not appending () to the function name.
window.onload = init/*()*/

function init() {
  // ...
}
  • appending () to a property name.
var x = Math.floor(Math.random() * canvas.width/*()*/
  • $(this) not $("this").

SETUP MY ZSH ENVIRONMENT

Steps of setting up zsh environment on my systems (Arch Linux, MacOS, Windows/Cygwin).

the z command

the fzf command

SETUP MY AWESOME WM ENVIRONMENT

Awesome WM let you maniplate system windows like using Vim, besides its bleeding fast window UI rendering & switching speed on *nix platform I’ve ever seen.

Below records my steps of setting up the Awesome window manager on my Arch Linux progressively.

Installing Awesome Packages

The awesome package is in the official repository of Arch Linux.

Better install Xephyr for testing cases.

sudo pacman -S awesome xorg-xephyr

Pulling Down My Awesome-Config Repository

The pulled down repo must be put in ~/.config/awesome, where awesome will correctly load the configuration resources.

mkdir ~/.config # if .config does not exist before.
cd ~/.config
git clone https://github.com/Mudox/awesome-config.git awesome
cd awesome
git submodule update --init --recursive

SETUP MY CYGWIN ENVIRONMENT

Cygwin – bring *nix command line user experence (paritially though) and efficiency onto Windows. Below is the steps of setting up the Cygwin environment on my Windows.

Why Cygwin over other tools.

Setup Cygwin

Cygwin path remapping

mintty setting

color

mintty color palette

ls_color

colorful manpage

colout

encoding

other settings

Shell environment setup

Cygwin package manager

Cygwin Using Tips

Working with gVim of Windows

Most of the time, I prefer gui version of Vim than terminal version for it being free of various shackles of terminal emulator, such as key confliction, color presentation limit, UI rendering efficiency limit, etc.

First make sure a gVim instance already exists outside of Cygwin.

When I need to handle off some files to gVim for Windows, I can use --remote (type :h clientserver in gVim for details) command families, for example:

alias gvim='/c/Program Files/Vim/vim74/gvim.exe'

gvim --remote-tab /path/of/file

it will open the file in new tab of an already running gVim instance.

ABOUT THE SITE

Note To Myself

When to use

<code>

  • in-line command line.

  • command name

  • package / software / application name offen appears in script code

  • file path

<strong>

  • single word or words that should be prominent in a sentence.

<em>

To-Do List of the Site

  • plural view customization.

  • list of content in sidebar for article single view.

  • top menu item more fancier.

  • tidy up CSS file.

  • term list view pagination.

  • home page.

  • add summary to each article.

  • chinese version of the site.

  • translation posts.

Acknowledgements

Hugo

A Fast and Flexible Static Site Generator built with love by spf13 in GoLang.

Hyde

Hyde is a brazen two-column hugo theme based on the Jekyll theme of the same name. It pairs a prominent sidebar with uncomplicated content.

JQuery

jQuery is a fast, small, and feature-rich JavaScript library. It makes things like HTML document traversal and manipulation, event handling, animation, and Ajax much simpler with an easy-to-use API that works across a multitude of browsers. With a combination of versatility and extensibility, jQuery has changed the way that millions of people write JavaScript.

Highlight.js

Highlight.js is a syntax highlighter written in JavaScript. It works in the browser as well as on the server. It works with pretty much any markup, doesn’t depend on any framework and has automatic language detection.

Node.js

Node.js® is a platform built on Chrome’s JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.

Bower

A package manager for the web.

Bower works by fetching and installing packages from all over, taking care of hunting, finding, downloading, and saving the stuff you’re looking for. Bower keeps track of these packages in a manifest file, bower.json. How you use packages is up to you. Bower provides hooks to facilitate using packages in your tools and workflows.

TagCanvas

TagCanvas is a Javascript class which will draw and animate a HTML5 canvas based tag cloud.

particles.js

A lightweight JavaScript library for creating particles.

normalize.css

A collection of HTML element and attribute style-normalizations.

animatescroll.js

A Simple jQuery Plugin for Animating Scroll

animate.css

A cross-browser library of CSS animations. As easy to use as an easy thing. http://daneden.github.io/animate.css

stroll.js

CSS3 list scroll effects http://lab.hakim.se/scroll-effects

mermaid.js

Generation of diagrams and flowcharts from text in a similar manner as markdown.

D3.js

D3.js is a JavaScript library for manipulating documents based on data. D3 helps you bring data to life using HTML, SVG and CSS. D3’s emphasis on web standards gives you the full capabilities of modern browsers without tying yourself to a proprietary framework, combining powerful visualization components and a data-driven approach to DOM manipulation.

gVim

the editor.

MY VIM CUSTOMIZATION POLICY

It is the Vim that bring we into the fantastic OSS world. Fiddling with it is full of surprise and happy.

Below records my thoughts and rules of customizing my Vim.

About Mapping

Good prefixes for normal mode mappings

The comma ,

use 2 ~ 3 suffix characters, then we can get more candidates key combinations for mapping.

The backslash \

different keyboard layouts have different locations for \, so it should be used less frequently than ,.

The space key <Space>

the <Space> is the best prefix for normal mappings I’ve ever found. It spans a long distance at the bottom of the keyboard, which makes it’s very easy and comfortable to touch.

currrently, I only assigned it to

The enter <Cr> or <Enter>

since many vim itself and many plugin use , so I should use it sparely. when a single click of is needed, you will feel a noticeable response lag.

The backspace key <BS>

by default, the <BS> acts the same as h, Ctrl-H and <Left> keys on normal mode. so I have substituted it with the <Enter> key as a main prefix.

other possible key for prefixes

  • <C-P>

  • <C-N>

  • =

Mapping toggling commands

  1. use co prefix, which is derived from tpope’s ‘unimpaired’ plugin.

  2. use ,*<Space> pattern, which is derived from scrooloose’s ‘NERD commenter’ plugin.

SWIFT OJECT - ORIENTED FEATURE

Learning notes about object oriented features of the Swift programming language.

Class Like Constructs In Swift

In Swift, enum, struct, class all can:

  1. have properties to keep states.

  2. have methods to perform actions.

  3. define subscript operators to let user access their properties through subscript syntax.

  4. define initializers to have a reasonable initial state.

  5. be extended to have additional behaviors beyond their default implementations.

  6. conform to protocols.

Only class can:

  1. have inheritance capability.

  2. have deinitializer.

  3. be referenced by mutiple variable or constants. the struct and enum are both value types.

Properties

stored properties

lazy properties

computed properties

shorthand setter syntax

shorthand read-only getter syntax

Initializers

JAVASCRIPT TYPE CONVERSIONS

Here records what I learned about JavaScript’s type conversion.

Sepcial Value Or Types In JavaScript

The undefined

The undefined is the only value of undefined, represents unknown value of any other types, including primitive types & object.

// play with 'undefined'
typeof undefiend                  /* undfeined        */
undefined == undefined            /* true             */
undefined == null                 /* true             */
undefined !== null                /* true             */
Boolean(undefined)                /* false            */
Number(undefined)                 /* NaN              */

The null

The null, by standards, should be the only value of null type, but in certain browser (e.g. firfox, chrome), it is of type object. null is used to represent unknown value of an object.

It is equal to itself and it is equal to undefined.

// play with 'null'
typeof null                       /* object           */
null == null                      /* true             */
null == undefined                 /* true             */
null !== undefined                /* true             */
Boolean(null)                     /* false            */
Number(null)                      /* 0                */

The NaN

The NaN is a Number that can not be represented as a number.

It dose NOT equal to itself, hence JavaScript provide a built-in function isNaN() to test if a value is a NaN.

// play with 'NaN'
typeof NaN                        /* number           */
NaN == NaN                        /* false            */
NaN == undefined                  /* false            */
NaN == null                       /* false            */
Boolean(NaN)                      /* false            */
Number(NaN)                       /* NaN              */
isNaN(NaN)                        /* true             */
NaN == 0/0                        /* true             */
isNaN(0/0)                        /* true             */

Implicit Type Conversions

When other types need to be converted into a number

When different types are mixed in a relational operation (i.e == != < <= > >=) except the === operator, or an arithmetic operation, except the + operator, they would be converted into numbers first.

For Boolean:

  • true would be converted to 1

  • false would be converted to 0

For String:

It is converted literally, i.e.

'2014' < 2 /* 2014 < 2 yields false */
'3.1415' == 3.1415 /* 3.1415 == 3.1415 yields true */

There is one exception: a emtpy string would be converted to 0.

var emptyText = '';

/* 'emptyText' here, converetd to 0, is compared to true which is converted to 1,
and then '!' negates the results to true */
if (!emptyText) {
  console.log('empty text is not true!')
}

When other types need to be converted into a string

The special + operator

In JavaScript, the + is first a string concatenation operator, then a arithmetic addition operator.

When one of +’s operands is a string, JavaScript will try to convert the other operand into a string, and perform a concatenation operation.

For Boolean:

  • true would be conveted bo “true”

  • false would be conveted to “false”

For null, undefined & NaN

they all be converted literally.

When other types need to be converted into a boolean value

from 《Head First JavaScript Programming》:

the secret to learning what is truthy and what is falsey is to learn what’s falsey, and then consider everything else truthy. concentrate on knowing what is falsey, and then everything else you can consider truthy.

it is a golden rule that also applys in many other programming language learning situations.

As to what value should be considered as falsey, different language has different policy. There are 5 falsey value in JavaScript:

  1. undefined

  2. null

  3. NaN

  4. ""

  5. 0

WEB PAGE LAYOUTS

Liquid Layout

This is the browser’s default layout behavior, if you did not add any CSS to style a page. The block elements, like liquid, just fill as much space as they can in the pages.

Frozen Layout

By using the CSS attribute combination of float and width, we can put a containing block (i.e. <seciton>, <aside>, <div>) to float on to left-most or right-most side forming a column, and let the remaining content to flow around the fixed-width floating column, forming the other column.

Use CSS attribute clear: [left | right] to let a block to layout fully underneath a floating elements.

Jello Layout

On the basis of frozen layout, we can use containing fixed-width block to wrap all columns (floating or flowing), and by using margin-left: auto; margin-right: auto; CSS style, to center the contained columns in the page.

Absolute Position

By using the CSS attribute combination of position: [absolute | fixed] and left | right | top | bottom: ..., we can take the column fully out of layout flow, and fix their position relative to the page (position: absolute), or to the viewport (position: fixed).

Table Display

Use CSS attribute display: [table | table-row | table-cell] to organize HTML elements into an invisible table.

Most of the time, vertical-align: top will help you to get what you want to see.

ABOUT ME

Hi, I’m Mudox.

I am also in:

GIT MISC

Alias

  • working tree, working directory

  • index, staging area, cache, staged snapshot

  • commit[ted] history, commit[ted] snapshot

The add & rm & reset & commit & checkout Sub-commands.

  • between the committed history & staging area

    • commit submit changes from staging area to committed history

    • reset revert changes from committed history back to staging area

  • between the staging area & working tree.

    • add submit changes from working tree to staging area, preparing for committing.

    • rm remove file(s) from stageing area, so they become untracked.

  • checkout restore changes from staging area or a specific commit of committed history to working directory.

  • reset

    • unstages changes in staging area. v git reset

    • or, if you ask for more, uncommits changes in history.

      git reset <commit-ish>
      
  • rm

    • untracks file(s) previously tracked in staging area.

      git rm --cache <paths>
      
    • or, if you ask for more, removes file(s) in the work directory.

      git rm <paths>
      
  • git reset vs git checkout

    • git reset <commit-ish> <paths> only update staging area.

    • git checkout <paths> fetch <paths> from staging area to working direcotry.

    • git checkout <commit-ish> fetch <paths> from history to both index & working direcotry.

The git Rebase Sub-command

Advantage of rebase:

  • no additional merge commit

  • linear commit history

Disadvantage of rebase:

  • safety

  • tracability: the evidences of merging are wiped away.

Golden rule of git rebase:

never use it on public branches.

When to use rebase

  • Local cleanup

  • Incorporating upstream changes into a feature branch

  • Integrating a approved feature

The reset, checkout And revert Sub-commands

The parameters that you pass to git reset and git checkout determine their scope. When you don’t include a <file path> as a parameter, they operate on whole commits. Note that git revert has no file-level counterpart

from atlassian’s git tutorials

Commit level operations

git reset --[soft | mixed | hard] <commit-ish> move branch tips backwards or even forwards, while affecting staging area & working direcotry according to options it is given.

option history staging area working directory
--soft
--mixed
--hard

git checkout <commit-ish> dose not move tips around.

git revert undo commits by adding a new commit. it is a safe (reversible) way to undo commits, while git reset is dangerous (irreversible) way to undo commits.

File level operations

git [reset|checkout] <commit-ish> <pathspec>
command history staging area working directory
reset
checkout

Summary

command commit level file level
reset discard commits in private branches or throw away uncommited changes unstage a file
checkout swtich between branches or inspect old snapshots discard changes in the working directory
revert undo commits in public branches N/A

COMPILE MACVIM & YCM ON OSX

Compiling Youcompleteme and Macvim on MacOSX once beaten me down for several nights.

I eventually found out that this is because the interference from pyenv and [homebrew][brew].

[homebrew][brew] installs packages into a unconventional path, which makes MacVim and Youcompleteme can found buidling dependencies in default paths.

While pyenv will shadow Macvim’s default python …

Preparation

  • disable pyenv

    1. run brew unlink pyenv (brew link pyenv after compilation)

    2. restart shell (e.g. itemr2)

  • reset develop directory of Xcode

    1. sudo xcode-select -r

Compile YCM

On MacOSX using native clang package has proven to be very stable, besides, it drastically accelerates the installing process – leaving install.sh no need to download the prebuild binaries from LLVM’s site.

cd /to/ycm/root/directory/
    ./install.sh --clang-completer --system-libclang

Compile MacVim

make distclean
./configure               \
    --with-features=huge  \
    -with-macarchs=x86_64 \
    --enable-perlinterp   \
    --enable-rubyinterp   \
    --enable-pythoninterp \
    --enable-luainterp    \
    --enable-perlinterp   \
    --enable-cscope       \
    --with-lua-prefix=/usr/local/Cellar/lua/<current_version> >/tmp/log
make

VIM CHAMELEON STARTUP MENU

Records here the steps of making a small and neat vim-chameleon startup screen.

On Windows:

  1. create a shortcut from gVim.exe.

  2. right click on the shorcut to open it’s property dialog.

  3. append the following lines (concatenated into one line) to the target field.

--cmd "let g:mdx_chameleon_cur_mode = 'startup'"
--cmd "set lines=9 columns=32"
--cmd "winpos 475 320"
-c "let &titlestring='Happy Vimming!'"
-c "ChamStartup"
  1. optionally, put this shortcut under paths listed in system’s $PATH environment variable.

On Mac OSX:

the MacVim.app does not accepts arguemnts above, we should use:

/Applications/MacVim.app/Contents/MacOS/Vim -g

instead:

/Applications/MacVim.app/Contents/MacOS/Vim -g            \
        --cmd "let g:mdx_chameleon_cur_mode = 'startup'"  \
        --cmd "set lines=9 columns=22"                    \
        --cmd "winpos 880 370"                            \
        -c "let &titlestring='Happy Vimming!'"            \
        -c "let &guifont = 'Monaco for Powerline:h16'"    \
        -c "ChamStartup"

On Linux:


GIT FLOW

1. Main Branches

  • the main branch

    keeps the official release history (usually with version nubmer tags attached).

    i.e. every commits in master is a new release. all branches merged back into master must have a new incremental version number.

  • the develop branch

    serves as an integration branch for features.

    nitghly build built from it.

2. Supporting Branches

2.1 feature (or topic) branches

branch off from: develop branch

merge into: develop branch

naming convention: any name except master, develop, relase[/-]*, hotfix[/-]*

# Branch A New Feature Branch Off From Develop Branch
git checkout -b some-feature develop
# Add Feature Commits To Branch Some-feature ...
# Merge Feature Branch Back Into Develop Branch.
git checkout develop
git merge --no-ff some-feature
git push origin develop

2.2 release branches

branch off from: develop branch

merge into: develop & master branch

naming convention: release/* or release-*

# Branch A New Release Branch Off From Develop Branch
git checkout -b release-<version number> develop
# Bummp Up Version In Related Fiels.
git commit -m 'Bumped version number to <version number>'
# Roll Out Release, Minor Bug Fixes
# Merge The Release Into Master, And Give It A New Tag.
git checkout master
git merge --no-ff release-<version number>
git tag -a <version number>
# Merge The Release Back Into Develop
git checkout develop
git merge --no-ff release-<version number>

2.3 hotfix (or maintenance) branches

branch off from: master branch merge into: develop & master branch if no active release branch existed currrently. naming convention: hotfix/* or hotfix-*

# Branch A New Hotfix Branch Off From Master Branch
git checkout -b hotfix-<version number> master
# Bummp Up Version In Related Fiels, Becuase It Will Finnaly Be Merged Back
# Into Master Branch.
git commit -m 'Bumped version number to <version number>'
# Roll Out Hotfix, Minor Bug Fixes
# Merge The Hotfix Into Master, And Give It A New Tag.
git checkout master
git merge --no-ff hotfix-<version number>
git tag -a <version number>
# Merge The Hotfix Back Into Develop
git checkout develop
git merge --no-ff hotfix-<version number>

GO'S TEMPLATE LIBRARY

I come across this library when I started to use Hugo, which says:

It is an extremely lightweight engine that provides a very small amount of logic. In our experience it is just the right amount of logic to be able to create a good static website.

3 Steps Using The Template Object

  1. New an template object.

  2. Parse template text.

  3. Execute (apply) the template to data structure.

6 Action Families

comment

{{/* comment here, line spanning allowed */}}

pipeline like variable expansion (substitution)

{{pipeline}}

if family for branching logic

{{if _pipline_}} T1 {{end}}
{{if _pipline_}} T1 {{else}} T0 {{end}}
{{if _pipline_}} T1 {{else if _pipeline_ }} T0 {{end}}

range family for iteration (loop)

{{range pipepine}} T1 {{end}}
{{range pipepine}} T1 {{else}} T0 {{end}}

with family for cursor (dot) moving

{{with pipeline}} T1 {{end}}
{{with pipeline}} T1 {{else}} T0 {{end}}

template family for tempates invocation

// with the dot '.' set to nil.
{{tempalte "name"}}
// with the dot '.' set to value of 'pipeline'.
{{tempalte "name" pipeline}}

Argument Types

  • untyped constants in go syntax

  • nil – the special constant

  • variable name

    $variable_name or $

  • . – the so called ‘context’ constant

  • dot chain consist of: field name, key name, niladic method name

(.Field.Key.Method args...).Field.Key ...
  • niladic function name

  • parenthesized group of above

print (func arg...) (.method arg...)

iOS NOTES - COCOA CONCURRENCY

Members Of Cocoa Concurrency

  • Operation Queue

    • abstract base class NSOperation

    • concrete subclass NSInvocation

    • concrete subclass NSBlockOperation

  • Dispatch Queue

  • Dispatch Source

Operation Queue Features

  1. graph-based dependencies

  2. completion block

  3. execution status monitoring

  4. prioritizeing

  5. canceling

iOS NOTES - COCOA THREADING

Run Loop

4 roles participate in the run loop game:

  1. Run Loop

    which is represented by NSRun Loop & CFRunLoop.

  2. Run Loop Mode

    which is represented by CFStringRef associated to each instance of run loop object.

  3. Run Loop Source

    which is represented by CFRunloopSource.

    • Input source

      • Port-based source

      • Perform selctor on other threads

      • Custom source

    • Timer

      which is represented by CFRunloopTimerRef.

      • Explictly defined timer

      • Perform selector on current thread with delay

      • Perform selector

  4. Run Loop Observer

4 ways to kill a run loop iteration:

  1. no sources exists

    since some system routines may install certain input sources to the run loop implictly, we should not kill a run loop iteration by clearing ‘all‘ sources we known.

  2. timeout

  3. sourced handled in one-shot mode

  4. explicitly stoped by CRunloopStop

3 kinds of perform selector sources.

on thread invocation delay blocking call? mode
current thread always non-blocking
other thread x x
main thread x x

Alternatives To Threaing

  1. Operation Objects

  2. Grand Central Dispatch (GCD)

  3. Idle-time notifications

  4. Asynchronous functions

  5. Timers

  6. Separate processes

Cocoa Support For Threading

  1. Cocoa threads

  2. POSIX threads

  3. Mutiprocessing Services (obsolete)

Inter-Thread Communication

  1. Direct messageing

  2. Global variables, shared memory & objects

  3. Conditions

  4. Run loop sources

  5. Ports & sockets

  6. Message queues (obsolete)

  7. Cocoa distributed objects

Synchronization Tools

  1. Atomic operation

    • atomic add

    • atomic increment

    • atomic decrement

    • compare-and-swap

    • test-and-set

    • test-and-clear

  2. Memory barriers

  3. Volatile variables

  4. Locks

    • Mutex

      • POSIX API provides pthread_lock_t

      • Cocoa provides NSLock & @synchronized()

    • Recursive lock

      which is provided as class NSRecursiveLock

    • Read-write lock (pthread only)

    • Distributed lock

    • Spin lock (not implemented)

    • Double-checked lock

  5. Conditions (aka condition variable)

  6. Perform selector routines