在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ iOS/ 自定義 Formatters
與四軸無人機的通訊
在沙盒中編寫腳本
結(jié)構(gòu)體和值類型
深入理解 CocoaPods
UICollectionView + UIKit 力學(xué)
NSString 與 Unicode
代碼簽名探析
測試
架構(gòu)
第二期-并發(fā)編程
Metal
自定義控件
iOS 中的行為
行為驅(qū)動開發(fā)
Collection View 動畫
截圖測試
MVVM 介紹
使 Mac 應(yīng)用數(shù)據(jù)腳本化
一個完整的 Core Data 應(yīng)用
插件
字符串
為 iOS 建立 Travis CI
先進的自動布局工具箱
動畫
為 iOS 7 重新設(shè)計 App
XPC
從 NSURLConnection 到 NSURLSession
Core Data 網(wǎng)絡(luò)應(yīng)用實例
GPU 加速下的圖像處理
自定義 Core Data 遷移
子類
與調(diào)試器共舞 - LLDB 的華爾茲
圖片格式
并發(fā)編程:API 及挑戰(zhàn)
IP,TCP 和 HTTP
動畫解釋
響應(yīng)式 Android 應(yīng)用
初識 TextKit
客戶端
View-Layer 協(xié)作
回到 Mac
Android
Core Image 介紹
自定義 Formatters
Scene Kit
調(diào)試
項目介紹
Swift 的強大之處
測試并發(fā)程序
Android 通知中心
調(diào)試:案例學(xué)習(xí)
從 UIKit 到 AppKit
iOS 7 : 隱藏技巧和變通之道
安全
底層并發(fā) API
消息傳遞機制
更輕量的 View Controllers
用 SQLite 和 FMDB 替代 Core Data
字符串解析
終身學(xué)習(xí)的一代人
視頻
Playground 快速原型制作
Omni 內(nèi)部
同步數(shù)據(jù)
設(shè)計優(yōu)雅的移動游戲
繪制像素到屏幕上
相機與照片
音頻 API 一覽
交互式動畫
常見的后臺實踐
糟糕的測試
避免濫用單例
數(shù)據(jù)模型和模型對象
Core Data
字符串本地化
View Controller 轉(zhuǎn)場
照片框架
響應(yīng)式視圖
Square Register 中的擴張
DTrace
基礎(chǔ)集合類
視頻工具箱和硬件加速
字符串渲染
讓東西變得不那么糟
游戲中的多點互聯(lián)
iCloud 和 Core Data
Views
虛擬音域 - 聲音設(shè)計的藝術(shù)
導(dǎo)航應(yīng)用
線程安全類的設(shè)計
置換測試: Mock, Stub 和其他
Build 工具
KVC 和 KVO
Core Image 和視頻
Android Intents
在 iOS 上捕獲視頻
四軸無人機項目
Mach-O 可執(zhí)行文件
UI 測試
值對象
活動追蹤
依賴注入
Swift
項目管理
整潔的 Table View 代碼
Swift 方法的多面性
為什么今天安全仍然重要
Core Data 概述
Foundation
Swift 的函數(shù)式 API
iOS 7 的多任務(wù)
自定義 Collection View 布局
測試 View Controllers
訪談
收據(jù)驗證
數(shù)據(jù)同步
自定義 ViewController 容器轉(zhuǎn)場
游戲
調(diào)試核對清單
View Controller 容器
學(xué)無止境
XCTest 測試實戰(zhàn)
iOS 7
Layer 中自定義屬性的動畫
第一期-更輕量的 View Controllers
精通 iCloud 文檔存儲
代碼審查的藝術(shù):Dropbox 的故事
GPU 加速下的圖像視覺
Artsy
照片擴展
理解 Scroll Views
使用 VIPER 構(gòu)建 iOS 應(yīng)用
Android 中的 SQLite 數(shù)據(jù)庫支持
Fetch 請求
導(dǎo)入大數(shù)據(jù)集
iOS 開發(fā)者的 Android 第一課
iOS 上的相機捕捉
語言標簽
同步案例學(xué)習(xí)
依賴注入和注解,為什么 Java 比你想象的要好
編譯器
基于 OpenCV 的人臉識別
玩轉(zhuǎn)字符串
相機工作原理
Build 過程

自定義 Formatters

我們希望有一種快速的一次性的解決方案,可以把數(shù)據(jù)格式化為一種易讀的格式。Foundation 框架中的就有 NSFormatter 可以很好地勝任這個工作。另外,在 Mac 上,Appkit 已經(jīng)內(nèi)建了 NSFormatter 的支持。

內(nèi)建格式器

Foundation 框架中的 NSFormatter 是一個抽象類,它有兩個已經(jīng)實現(xiàn)的子類:NSNumberFormatterNSDateFormatter?,F(xiàn)在我們先跳過這些,來實現(xiàn)我們自己的子類。

如果你想了解更多的相關(guān)知識,我推薦閱讀 NSHipster。

介紹

NSFormatter 除了拋出錯誤,其它什么事也不做。我還不知道有人想要用這個,當(dāng)然如果它對你有用,就去用它吧。

因為我們不喜歡錯誤,我們在此實現(xiàn)一個 NSFormatter 的子類,它可以把 UIColor 實例轉(zhuǎn)換成可讀的名字。例如,以下代碼可以返回字符串“Blue”:

KPAColorFormatter *colorFormatter = [[KPAColorFormatter alloc] init];
[colorFormatter stringForObjectValue:[UIColor blueColor]] // Blue

NSFormatter 的子類化有兩個方法需要實現(xiàn):stringForObjectValue:getObjectValue:ForString:errorDescription:。我們先開始介紹第一個方法,因為這個方法更常用。第二個方法,就我所知,經(jīng)常用于 OS X 上,并且通常不是很有用,我們將稍后介紹。

初始化

首先,我們需要做些初始化的工作。由于沒有事先定義好的字典可以把顏色映射至名字,這些工作將由我們來完成。為了簡化,這些工作將在初始化方法中完成:

- (id)init;
{
    return [self initWithColors:@{
        [UIColor redColor]: @"Red",
        [UIColor blueColor]: @"Blue",
        [UIColor greenColor]: @"Green"
    }];
}

這里的 colors 是一個以 UIColor 實例為鍵,英語名為值的字典。大家可以自行地去實現(xiàn) initWithColors: 方法。當(dāng)然你也可以自行實現(xiàn),或者直接前往 Github repo 獲得答案。

格式化對象值

由于我們這里只可以格式化 UIColor 實例對象,于是在方法 stringForObjectValue: 中的第一件事就是判斷傳入的參數(shù)類型是否是 UIColor 類。

- (NSString *)stringForObjectValue:(id)value;
{
    if (![value isKindOfClass:[UIColor class]]) {
        return nil;
    }

    // To be continued...
}

在判斷參數(shù)合法后,我們可以實現(xiàn)真正的邏輯了。我們的格式器中包含一個 UIColor 對象為鍵,顏色名為值的字典。因此,我們只需要以 UIColor 對象為鍵找到對應(yīng)的值:

- (NSString *)stringForObjectValue:(id)value;
{
    // Previously on KPAColorFormatter

    return [self.colors objectForKey:value];
}

以上代碼是一個盡可能簡單的實現(xiàn)。一個更高級(有用)的格式器應(yīng)該是在我們的顏色字典中沒有找到匹配的顏色時,返回一個最接近的顏色。大家可以自行實現(xiàn),或是你不想花費太多功夫,可以前往 Github repo。

反向格式化

我們的格式器也應(yīng)該支持反向格式化,即把字符串轉(zhuǎn)成實例對象。這是通過 getObjectValue:forString:errorDescription: 方法實現(xiàn)。在 OS X 上,在使用 NSCell 時會經(jīng)常用到這個方法。

NSCell 有一個 objectValue 屬性。默認情況下,NSCell 會用 objectValue 的描述,但是它也可以選擇用一個格式器。在用 NSTextFieldCell 時,用戶可以輸入值,作為程序員,我們可能期望 objedctValue 可以根據(jù)根據(jù)輸入的字符串轉(zhuǎn)成一個 UIColor 實例。例如,用戶如果輸入“Blue”,我們需要返回一個 [UIColor blueColor] 實例的引用。

實現(xiàn)反向格式化分為兩部分:一部分為當(dāng)格式器可以成功地把字符串轉(zhuǎn)成 UIColor 實例,另一部分當(dāng)其不能成功轉(zhuǎn)換。第一部分代碼如下:

- (BOOL)getObjectValue:(out __autoreleasing id *)obj 
             forString:(NSString *)string 
      errorDescription:(out NSString *__autoreleasing *)error;
{
    __block UIColor *matchingColor = nil;
    [self.colors enumerateKeysAndObjectsUsingBlock:^(UIColor *color, NSString *name, BOOL *stop) {
        if([name isEqualToString:string]) {
            matchingColor = color;
            *stop = YES;
        }
    }];

    if (matchingColor) {
        *obj = matchingColor;
        return YES;
    } // Snip

這里可以做一些優(yōu)化,但是我們先不去做這些。以上方法會遍歷我們顏色字典里的每一個對象 ,當(dāng)一個顏色名字找到時,則會返回其對應(yīng)關(guān)聯(lián)的 UIColor 實例對象的引用,同時返回 YES 告知調(diào)用者我們已經(jīng)成功地把字符串轉(zhuǎn)成了一個 UIColor 實例對象。

現(xiàn)在處理第二部分:

if (matchingColor) {
    // snap
} else if (error) {
    *error = [NSString stringWithFormat:@"No known color for name: %@", string];
}

return NO;

這里,我們?nèi)绻荒苷业揭粋€匹配的顏色,我們會檢測調(diào)用者是否需要錯誤信息,如果需要,則把錯誤通過引用返回。這里檢查錯誤很重要。如果你不這樣做,程序就會 crash。同時,我們也會返回 NO,告知調(diào)用者這次轉(zhuǎn)換失敗。

本地化

到現(xiàn)在,我們已經(jīng)建立了一個完全功能的 NSFormatter 的子類,當(dāng)然這只是對于生活在美國的英語使用者而言有用。

但相比全世界 71.3 億人,那才 3.19 億?;蛘哒f,你還有 96% 的潛在用戶。當(dāng)然你可以說:這些潛在用戶絕大部分都不是 iPhone 或 Mac 使用者,這么做有什么意思呢?這么想你就太掃興了。

NSNumberFormatterNSDateFormatter 都有一個 locale 屬性,它是 NSLocale 實例對象。我們現(xiàn)在來擴展格式器以支持本地化,讓它可以根據(jù) local 屬性來返回對應(yīng)翻譯的名字。

翻譯

首先,我們需要翻譯顏色名字字符串。有關(guān) genstring 與 *.lprojs 超出了本文的范圍。有很多文章討論這點。好了,不需要其它工作了,快要結(jié)束了。

本地化的格式化

接下來是本地化功能的實現(xiàn)。在獲取翻譯的字符串后,我們需要更新 stringForObejectValue: 方法。以前已經(jīng)使用過 NSLocalizedString 的人可能已經(jīng)早早的把每一個字符串都用 NSLocalizedString 替換了。但是我們不會這么做。

我們現(xiàn)在處理的是一個動態(tài)的 local,而 NSLocalizedString 只會查找當(dāng)前默認的語言的翻譯。在99%的情況下,這種默認的行為是你所想要的,但是我們會用格式化器的 locale 屬性來動態(tài)查詢語言。

以下是 stringForObjectValue: 的新的實現(xiàn):

- (NSString *)stringForObjectValue:(id)value;
{
    // Previously on... don't you hate these? I just watched that 20 seconds ago!

    NSString *languageCode = [self.locale objectForKey:NSLocaleLanguageCode];
    NSURL *bundleURL = [[NSBundle bundleForClass:self.class] URLForResource:languageCode 
                                                              withExtension:@"lproj"];
    NSBundle *languageBundle = [NSBundle bundleWithURL:bundleURL];
    return [languageBundle localizedStringForKey:name value:name table:nil];
}

上面的代碼還有可以重構(gòu)改進的地方,但因為把代碼都放在同一個地方可以方便閱讀,所以請大家多多包涵了。

首先,我們通過 locale 屬性查找相應(yīng)的語言,之后通過 NSBundle 找到對應(yīng)的語言代碼。最后,我們會讓 bundle 對英語名稱進行翻譯。如果找不到對應(yīng)的翻譯,則會返回 name: 方法的參數(shù)(即英語名稱)。如上即是 NSLocalizedString 的具體實現(xiàn)。

本地化的反向格式化

同樣,我們也可以把顏色名稱轉(zhuǎn)成 UIColor 實例對象,當(dāng)然,我認為這樣做是不值得的。我們當(dāng)前的實現(xiàn)適用于99%的情況。另外1%的情況是在 Mac 的 NSCell 上使用,而且你允許用戶輸入一個你試圖解析的顏色的名字,這所需要做的要比簡單的 子類化 NSFormatter 復(fù)雜很多。或許,你不應(yīng)該允許你的用戶通過文本輸入顏色值。NSColorPanel 在這里是一個更好的解決方案。

屬性化字符串

到目前為止,我們的格式器都按我們預(yù)期的工作。接下來讓我們做一個完全沒用的功能,只是示范一下我們可以這么做,你懂的。

格式器同時支持屬性化字符串。要不要支持它取決于你特定的應(yīng)用與其用戶界面。因此,你最好把這個功能做成可配置。

以下代碼就是將文本顏色設(shè)置為當(dāng)前正在格式化的顏色:

- (NSAttributedString *)attributedStringForObjectValue:(id)value 
                                 withDefaultAttributes:(NSDictionary *)defaultAttributes;
{
    NSString *string = [self stringForObjectValue:value];

    if  (!string) {
        return nil;
    }

    NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithDictionary:defaultAttributes];
    attributes[NSForegroundColorAttributeName] = value;
    return [[NSAttributedString alloc] initWithString:string attributes:attributes];
}

首先,我們?nèi)缰耙粯犹幚碜址缓髾z查格式化是否成功。然后我們把默認的屬性值與前面設(shè)置的顏色屬性結(jié)合后,最終返回屬性化字符串。很容易,是嗎?

便捷

因為初始化內(nèi)建的格式器太慢了,所以通常需要對外給你的格式器提供一個便利的類方法。這個格式器應(yīng)該用默認值與當(dāng)前的本地化環(huán)境。以下是格式器的實現(xiàn):

+ (NSString *)localizedStringFromColor:(UIColor *)color;
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        KPAColorFormatterReusableInstance = [[KPAColorFormatter alloc] init];
    });

    return [KPAColorFormatterReusableInstance stringForObjectValue:color];
}

除非你的格式器像 NSNumberFormatterNSDateFormatter 一樣做一些瘋狂的事情 ,你可能不需要因為性能問題這么做。但是這樣做也可以讓使用格式器簡單許多。

總結(jié)

我們的顏色格式器現(xiàn)在可以把一個 UIColor 實例格式成一個可讀的名字或是反過來也行。當(dāng)然還有放多有關(guān) NSFormatter 的事情沒有涉及。特別是在 Mac 上,因為它跟 NSCell 相關(guān),你可以用更多高級的特性。例如當(dāng)用戶在編輯的時,你可以對字符串做一些檢測。

我們的格式器還可以做更多自定義的事情。例如,在沒查找到一個你需要的顏色名字時,我們可以返回給你最相近的顏色名字。有時,你可能需要我們的格式器有一個 Boolean 屬性來控制該功能?;蛟S我們的屬性化字符串的格式化不是你想要的,并且應(yīng)該支持更多自定義操作。

就此,我們完成了一個非常可靠的格式器。所有的代碼(伴有 OS X 示例)都放在了 Github 上, 并且你也可以在 CocoaPods 上看到。如果你應(yīng)用需要此功能,可以將 "KPAColorFormatter" 放在你的 Podfile 中,開始使用它吧。

上一篇:自定義控件下一篇:MVVM 介紹