最近接到了一個老闆的需求,要把咱們的程序進行國際化,就是新增一個英語的支持。
大體的需求是這個樣子的:程序內添加語言切換選項,並在第一次安裝的時候自動選擇合適的語言(中文系統的手機(不管簡體中文繁體中文)一概使用簡體中文,其它語言的(不管英語仍是法語德語)都默認使用英文)。
其實若是隻是添加多語言支持,再也不應用內切換語言,蘋果的開發就能很好的支持了。就是多了這個應用內切換語言(像微信那樣),邏輯就複雜了不少。
由於以前的時候字符串都是寫死在程序中的,因此不可能大範圍的更改。又要涉及到語言的切換,因此,只能用一個折中的方法,寫個宏去處理。
實現的邏輯大約是這個樣子的:userdefaults存一個用戶設置的語言,若是沒有存儲就根據系統的語言去作邏輯判斷,最終獲得肯定使用哪一種語言而後再去讀取相應的語言文件,根據key-value去查找,若是查找不到就默認的使用key做爲value使用了。
邏輯大約應該是這樣的:html
//OC [[NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@",([[[NSUserDefaults standardUserDefaults] objectForKey:@"Language"] hasPrefix:@"zh"] || ([[NSUserDefaults standardUserDefaults] objectForKey:@"Language"] == nil && [[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode] hasPrefix:@"zh"]))?@"zh-Hans":@"en"] ofType:@"lproj"]] localizedStringForKey:(key) value:key table:nil]; //swift func L(key:String) -> String { var language:String? = NSUserDefaults .standardUserDefaults().objectForKey("Language") as? String if language == nil { language = NSLocale.currentLocale().objectForKey(NSLocaleLanguageCode)! as? String } let bundle:NSBundle = NSBundle.init(path: NSBundle.mainBundle().pathForResource(((language!.hasPrefix("zh")) ? "zh-Hans" : "en"), ofType: "lproj")!)! return NSLocalizedString(key, tableName: nil, bundle: bundle, value: key, comment: key) }
以上的key就是宏的形參了。swift
這樣的宏實際上是在編譯以前就進行了代碼的替換,其實就是把工程的全部的相關的地方替換上了這麼長的代碼,而後再進行編譯(swift的實際上是用一個public的函數去處理的,不是代碼替換)。微信
後來發現有個更好的東西能夠替換這個,就是內聯函數函數
內聯函數首先是一個函數,能夠有函數的參數檢查的優點spa
有普通的函數不具有的優點,函數的代碼本質是放在符號表中的,使用的時候進行替換,沒有了普通函數調用的時候的開銷.net
執行效率和宏定義本質是同樣的(內聯函數是編譯器首先在函數調用處使用函數體自己語句替換了函數調用語句,而後編譯替換後的代碼),可是還有優點code
更多的內聯函數的定義仍是放幾個博客吧:orm
http://blog.csdn.net/sqc3375177/article/details/8264778htm
http://blog.csdn.net/chsadin/article/details/47982923blog
http://www.cnblogs.com/QG-whz/p/4641479.html
OC的差很少這個樣子寫法:
static inline NSString * L (NSString * key) { return [[NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@",([[[NSUserDefaults standardUserDefaults] objectForKey:@"Language"] hasPrefix:@"zh"] || ([[NSUserDefaults standardUserDefaults] objectForKey:@"Language"] == nil && [[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode] hasPrefix:@"zh"]))?@"zh-Hans":@"en"] ofType:@"lproj"]] localizedStringForKey:(key) value:key table:nil]; }
swift的這樣就能夠了
@inline(__always) func L(key:String) -> String { var language:String? = NSUserDefaults .standardUserDefaults().objectForKey("Language") as? String if language == nil { language = NSLocale.currentLocale().objectForKey(NSLocaleLanguageCode)! as? String } let bundle:NSBundle = NSBundle.init(path: NSBundle.mainBundle().pathForResource(((language!.hasPrefix("zh")) ? "zh-Hans" : "en"), ofType: "lproj")!)! return NSLocalizedString(key, tableName: nil, bundle: bundle, value: key, comment: key) }
@inline後面的括號裏面能夠有兩種關鍵詞「never」和「__always」naver是能夠避免這個替代的時候使用了過大的代碼塊。這個到底使用普通函數仍是內聯函數是由編譯器決定的(若是內聯函數裏面有循環和開關語句)就直接和普通函數沒什麼區別了__always其實就是程序的運行效率優先了,無論什麼,直接按照內聯函數對待了總結一下,就是之後寫有參宏的時候直接用內聯函數就行了,寫代碼有提示還能儘量的保證不出錯。