2014/9/26

Swift Optional 變數的處理方法

在學習 Swift 語法的時候,我遇到最大的障礙是 Optional(!?)。驚嘆號跟問號和型別轉換的問題,這兩個符號寫在變數型別上時,定義了變數是否可以為空值(nil),以及變數預設為空值(?)或預設為有值(!)。在語言設計上,我們可以知道 Apple 會這樣設計,目的是為了寫程式的人必須處理當變數為空值時的情形,這是為了程式的安全性。

在變數宣告上寫作

var s:String = "s"
var s0:String!
var s1:String! = "s1"
var ss0:String?
var ss1:String? = "ss1"

其中s不可為空值,s0, s1, ss0, ss1 可為空值,s0, s1 預設不為空值,ss0, ss1 預設為空值。
在變數使用上,假設我們現在要做的事情是取得字串長度,預設為空值的變數必須經過一個轉換才能使用,基本的用法如下:


1. 用 lf let 解開變數封裝
var stringLength1:Int = 0
if let ss0 = ss0 {
    //如果ss0有值會進入這裡,且ss0的型別被改為String
    stringLength1 = ss0.utf16Count
}
else
{
    //如果是空值會進入這裡
}


2. 用問號,當 ss0 是 nil 時 return nil ,所以等號左邊必須也用可為空值的變數去接
var stringLength2:Int!
stringLength2 = ss0?.utf16Count


3. 用驚嘆號強制解開變數封裝,這種寫法當 ss0 是 nil 時程式就 crash
var stringLength3:Int
stringLength3 = ss0!.utf16Count

方法 1 清楚地描述了 ss0 是空值或不是空值分別該怎麼做。
方法 2 是說當 ss0 是空值時,stringLength2 就設為空值。
方法 3 則是當 ss0 是空值時,程式就要 crash。

方法 1 或方法 2 都有處理當 ss0 為 nil 時該怎麼做,而方法 3 沒有,所以方法 3 是危險的。
也許我們可以當 ss0 為空值時給 ss0 一個預設值,讓程式繼續執行下去,做法如下:
if ss0 == nil {
   ss0 = "nil" 
}


ss0 = ss0 == nil ? "nil" : ss0

我們把設定預設值的動作寫成函數,以便日後使用。
public func unwarp(string:String?) -> String{
    return string == nil ? "nil" : string!
}
unwarp(ss0)
// return "nil"
unwarp(ss1)
// return "ss1"

我們也可以也把它寫成泛型,並且加入預設值的設定。
public func unwarp<T>(value:T?, defaultValue:T) -> T{
    return value == nil ? defaultValue : value!
}
unwarp(ss0, "XDDD")
// return "XDDD"
unwarp(ss1, "XDDD")
// return "ss1"

於是我們可以對所有型別都做出 unwarp function。


***  2014/10/9 更新  ***
上述的泛型 unwarp 函數在輸入的兩個變數型別不同時會以 value 為主
以下的 code 修正這個問題,改為以 defaultValue 的型別為主

public func unwarp(value:AnyObject?, defaultValue:T)->T{
    if let value: AnyObject = value {
        return value is T ? value as T : defaultValue
    }else{
        return defaultValue
    }
}
unwarp("1.0",0.0)
// return 0.0
unwarp(1.0,0.0)
// return 1.0
unwarp(nil,0.0)
// return 0.0
var a1:Int = unwarp(3.5,1.5)
// a1 = 3
var a2:Int = unwarp("3.5",1.5)
// a2 = 1


***  2015/2/12 更新  ***
發現內建處理解開封印時加入預設值的運算子 ??

var ss:String?
ss ?? "QQ"
// return QQ

2014/9/5

有一種人在出手前,就已經確定他會成功,你覺得他是哪種人?

很多人都知道作事情的方法是

1. 事前準備:包含收集資料、分析、規劃等
2. 實作
3. 完成

如果不考慮失敗的話當然是這樣沒錯,一旦考慮失敗的話,方法就變成這樣:「事前準備→實作→失敗→調整→實作→失敗→調整→實作→失敗→調整→實作→失敗...」,不知道失敗了幾次,最後終於成功。


有一種人在出手前,就已經確定他會成功,你覺得他是哪種人?

1. 他以前作過,而且他成功了。
2. 他收集了很多資料,爬了很多文,作了很多分析,寫了很多規劃,下了很多苦工,但是他沒作過。


答案應該很明顯。如果你還在事前準備,那你打算什麼時候才開始實作?如果實作成本不高,那就該盡早實作,並且作紀錄,做好失敗的心理準備,根據紀錄來推斷該怎麼調整,嗯?這不就是作實驗的方法嗎?

最近在看的影片,真的很棒。


2014/9/3

關於 iBeacon

為什麼,商店老闆發現他可以當你在商店門口時立即發一份 coupon 給你,老闆們就高潮了?難道老闆們平常不發coupon?不是的,因為一個東西的價值,是根據環境決定。

一包衛生紙沒有什麼價值。但是當你在廁所裡大完便,發現只剩一張衛生紙,你卻會小心翼翼的使用他。

一瓶礦泉水沒有什麼價值。但是當你在沙漠裡,已經不記得上一次喝水是什麼時候,看著你手上唯一的一瓶礦泉水,卻捨不得喝。

當東西處於一個被需要的環境時,價值可能會超乎想像。而 iBeacon 可以幫助你抓住這個時機。

看看網路上對於 iBeacon 的應用,可以知道大部分提供的服務內容是原本就有提供的服務,而改變的是服務的時機。正因為提供服務的時機改變了,其價值就上升了。當你在使用者最需要地圖的時候,給他地圖,地圖的價值就上升了,沒人注意到的是地圖可能早就公開在網路上。

也就是說,如果要發想 iBeacon 可以作什麼?我認為把現有服務調整到使用者真的需要這項服務的時機,是 iBeacon 最應該做的。並不是不考慮那些原本就從未被滿足的需求,而是從那裡出發,很難具體地想像出一個正確的 iBeacon 服務。