使用Realm+YYModel+AFNetworking構(gòu)建一個簡易的app

之前寫了一篇使用Realm的一些總結(jié)的文章,然后里面說會總結(jié)一下使用Realm+YYModel+AFNetworking進行項目開發(fā)的經(jīng)驗撵枢,所以這篇就是啦。

想法

第一時間想到的就是市面上最常見的展示類應用精居,api的話我選擇了V2EX社區(qū)的api锄禽,簡單的用了一個獲取所有節(jié)點的api(v2ex社區(qū)api文檔看這里),簡單的使用UITableView展示所有的節(jié)點靴姿。最終效果如下如所示:

Paste_Image.png

開工

準備工作
  1. 新建項目沃但,使用Cocoapods管理依賴包,添加AFNetworking佛吓,Realm宵晚,YYModel這三個庫垂攘,非常基礎的東西不多寫了淤刃。
  2. 準備好獲取所有節(jié)點的api:http://www.v2ex.com/api/nodes/all.json
封裝AFNetworking(以下簡稱AFN)

由于Realm原生不支持JSON解析晒他,這篇文章也主要是是為了看如果將Realm與YYModel結(jié)合使用,但是我還是決定先封裝一下HTTP請求逸贾。
AFN 3.0之后陨仅,網(wǎng)絡請求的發(fā)起主要依賴AFHTTPSessionManager這個類,我們首先自定義一個單例類SessionManager 繼承自AFHTTPSessionManager

#import <AFNetworking/AFNetworking.h>

typedef void(^Success)(id data);
typedef void(^Failure)(NSURLSessionDataTask *task, NSError *error);

@interface SessionManager : AFHTTPSessionManager
+ (instancetype)shareManager;

//為了篇幅限制只在文章中展示get請求
- (NSURLSessionDataTask *)GETWithUrl:(NSString *)url params:(NSDictionary *)params success:(Success)success failure:(Failure)failure;
+ (NSURLSessionDataTask *)GETWithUrl:(NSString *)url params:(NSDictionary *)params success:(Success)success failure:(Failure)failure;
@end
#import "SessionManager.h"

static NSString *const kBaseURL = @"http://www.v2ex.com/api/";
typedef NS_ENUM(NSInteger, APIMethod) {
    APIMethodGET,
    APIMethodPOST,
    APIMethodPUT,
    APIMethodDELETE,
};

@implementation SessionManager
+ (instancetype)shareManager {
    static SessionManager *manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[self alloc] init];
    });
    return manager;
}

- (instancetype)init {
    self = [super initWithBaseURL:[NSURL URLWithString:kBaseURL]];
    self.requestSerializer = [AFHTTPRequestSerializer serializer];
    self.responseSerializer = [AFHTTPResponseSerializer serializer];
    self.requestSerializer.timeoutInterval = 30;
    return self;
}

//instance method
- (NSURLSessionDataTask *)GETWithUrl:(NSString *)url params:(NSDictionary *)params success:(Success)success failure:(Failure)failure {
    return [self requestWithMethod:APIMethodGET url:url params:params success:success failure:failure];
}

//class method
+ (NSURLSessionDataTask *)GETWithUrl:(NSString *)url params:(NSDictionary *)params success:(Success)success failure:(Failure)failure {
    return [[self shareManager] GETWithUrl:url params:params success:success failure:failure];
}

- (NSURLSessionDataTask *)requestWithMethod:(APIMethod)method url:(NSString *)url params:(NSDictionary *)params success:(Success)success failure:(Failure)failure {

    if (![url hasPrefix:@"http"]) {
        url = [[self class] reponseUrl:url];
    }
    if ([url rangeOfString:@":id"].length > 0 ) {
        NSAssert(NO, @"路徑 「%@」中有需要替換的id", url);
    }
    NSURLSessionDataTask *task = nil;
    switch (method) {
        case APIMethodGET: {
            task = [self GET:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                [self handleTask:task response:responseObject success:success];
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                [self handleTask:task error:error failure:failure];
            }];
            break;
        }
       //other case
       //...
    }
    return task;
}

+ (NSString *)reponseUrl:(NSString *)url{
    NSString *result = url;
    result = [NSString stringWithFormat:@"%@\%@", kBaseURL, result];
    return  result;
}

#pragma mark - handle response
- (void)handleTask:(NSURLSessionDataTask *)task response:(id)responseOject success:(Success)success {
    if (success) {
        success(responseOject);
    }
}

- (void)handleTask:(NSURLSessionDataTask *)task error:(NSError *)error failure:(Failure)failure{
   //handle error
}
@end

說明一下:我們的請求manager創(chuàng)建的時候铝侵,會基于http://www.v2ex.com/api/這個baseUrl創(chuàng)建灼伤,習慣RESTful API的對這個也習以為常了,同時在實例化的時候我們使用了requestSerializer 哟沫、responseSerializer饺蔑,并且設置每次請求超時時長為30秒。

封裝API

現(xiàn)在對于AFN的基本封裝工作已經(jīng)完成嗜诀,接下來只需要搞定每個API了猾警,我們新建一個V2EXAPIManager類繼承自剛才的SessionManager,在接口的實現(xiàn)中補全接口:

#import "SessionManager.h"
#import <AFNetworking.h>
#import "Node.h"

@interface V2EXAPIManager : SessionManager

- (NSURLSessionDataTask *)getAllNodeSuccess:(Success)success failurl:(Failure)failure;
@end
#import "V2EXAPIManager.h"

static NSString *allNodelUrl = @"nodes/all.json";

@implementation V2EXAPIManager

- (NSURLSessionDataTask *)getAllNodeSuccess:(Success)success failurl:(Failure)failure {
    return [self GETWithUrl:allNodelUrl params:nil success:^(id data) {

        NSArray <Node*>*allNodes = [NSArray yy_modelArrayWithClass:[Node class] json:data];
        if (success) {
            success(allNodes);
        }
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        if (failure) {
            failure(task,error);
        }
    }];
}
@end

有了BaseUrl隆敢,接下來只需要的發(fā)起請求的時候发皿,拼接上具體的需要訪問服務器的資源,這里是nodes/all.json拂蝎。

新建可用于持久化的Node模型

通過log我們可以看到穴墅,得到的是這樣json串,映射到iOS中則是一個包含多個字典的數(shù)組温自。

[
  {
    "id": 1,
    "name": "babel",
    "url": "http://www.v2ex.com/go/babel",
    "title": "Project Babel",
    "title_alternative": "Project Babel",
    "topics": 1119,
    "header": "Project Babel - 幫助你在云平臺上搭建自己的社區(qū)",
    "footer": "V2EX 基于 Project Babel 驅(qū)動玄货。Project Babel 是用 Python 語言寫成的,運行于 Google App Engine 云計算平臺上的社區(qū)軟件悼泌。Project Babel 當前開發(fā)分支 2.5松捉。最新版本可以從 <a href=\"http://github.com/livid/v2ex\" target=\"_blank\">GitHub</a> 獲取。",
    "created": 1272206882
  },
  ...
  ...
]

接下來就是根據(jù)拿到的數(shù)據(jù)字段建立我們的Node模型了,在使用Realm的時候需要我們的數(shù)據(jù)模型繼承自RLMObject馆里,同時為了使用YYModel,我們需要遵循<YYModel>協(xié)議:

#import <Realm/Realm.h>
#import <YYModel/YYModel.h>

@interface Node : RLMObject<YYModel>

@property NSString *ID;
@property NSString *name;
@property NSString *url;
@property NSString *title;
@property NSString *title_alternative;
@property NSInteger topics;
@property  NSString *header;
@property  NSString *footer;
@property NSDate *created;
@end
#import "Node.h"

@implementation Node

+ (NSString *)primaryKey {
    return @"ID";
}

+ (NSArray<NSString *> *)indexedProperties {
    return @[@"ID"];
}

//由于`id`字段會與系統(tǒng)關鍵字沖突隘世,我們可以手動轉(zhuǎn)換為大寫`ID`
+ (NSDictionary<NSString *,id> *)modelCustomPropertyMapper {
    return @{@"ID":@"id"};
}
@end

為了方便以后的使用以及提高查詢速度,我們使用ID作為主鍵與索引字段鸠踪。
這樣就可以在請求到數(shù)據(jù)之后使用

 NSArray <Node*>*allNodes = [NSArray yy_modelArrayWithClass:[Node class] json:data];

直接將數(shù)據(jù)轉(zhuǎn)換為存放節(jié)點Node的數(shù)組丙者。

在控制器里面發(fā)起請求并持久化
- (void)getNodes {
    [[V2EXAPIManager shareManager] getAllNodeSuccess:^(id data) {
        NSArray *nodes;
        if ([data isKindOfClass:[NSArray class]]) {
            nodes = data;
        }
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            @autoreleasepool {
                //delete old data
                RLMRealm *realm = [RLMRealm defaultRealm];
                [realm beginWriteTransaction];
                [realm deleteAllObjects];
                [realm commitWriteTransaction];
                
                //add new data
                [realm beginWriteTransaction];
                for (Node *node in nodes) {
                    [realm addObject:node];
                }
                [realm commitWriteTransaction];
                
                //retrieve data and reload data in main thread
                dispatch_async(dispatch_get_main_queue(), ^{
                    RLMRealm *mainThreadRealm = [RLMRealm defaultRealm];
                    self.nodes = [Node allObjectsInRealm:mainThreadRealm];
                    [self.tableview reloadData];
                });
            }
        });
    } failurl:^(NSURLSessionDataTask *task, NSError *error) {
        self.nodes = [Node allObjects];
        [self.tableview reloadData];
    }];
}

其他將數(shù)據(jù)渲染到UI上的一些代碼就不往上貼了,當然营密,本例也是非的簡陋械媒,例如封裝請求的錯誤處理也沒有做,也沒有多余的UI設計评汰,不過我們可以看到滥沫,使用Realm+YYModel完成一個從遠程請求數(shù)據(jù)并在本地持久化的需求非常簡單侣集,關鍵代碼甚至沒有幾行。
你可以在GitHub直接clone這個Repository

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末兰绣,一起剝皮案震驚了整個濱河市世分,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缀辩,老刑警劉巖臭埋,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異臀玄,居然都是意外死亡瓢阴,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門健无,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荣恐,“玉大人,你說我怎么就攤上這事累贤〉拢” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵臼膏,是天一觀的道長硼被。 經(jīng)常有香客問我,道長渗磅,這世上最難降的妖魔是什么嚷硫? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮始鱼,結(jié)果婚禮上仔掸,老公的妹妹穿的比我還像新娘。我一直安慰自己医清,他們只是感情好起暮,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著状勤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪双泪。 梳的紋絲不亂的頭發(fā)上持搜,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機與錄音焙矛,去河邊找鬼葫盼。 笑死,一個胖子當著我的面吹牛村斟,可吹牛的內(nèi)容都是我干的贫导。 我是一名探鬼主播抛猫,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼孩灯!你這毒婦竟也來了闺金?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤峰档,失蹤者是張志新(化名)和其女友劉穎败匹,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體讥巡,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡掀亩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了欢顷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片槽棍。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖抬驴,靈堂內(nèi)的尸體忽然破棺而出炼七,到底是詐尸還是另有隱情,我是刑警寧澤怎爵,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布特石,位于F島的核電站,受9級特大地震影響鳖链,放射性物質(zhì)發(fā)生泄漏姆蘸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一芙委、第九天 我趴在偏房一處隱蔽的房頂上張望逞敷。 院中可真熱鬧,春花似錦灌侣、人聲如沸推捐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽牛柒。三九已至,卻和暖如春痊乾,著一層夾襖步出監(jiān)牢的瞬間皮壁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工哪审, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蛾魄,地道東北人。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像滴须,于是被迫代替她去往敵國和親舌狗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫扔水、插件痛侍、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,058評論 4 62
  • 在Xcode6,有另一種選擇铭污。您可以指定一個故事板恋日,其初始視圖控制器 用作應用程序的啟動畫面。 1嘹狞,創(chuàng)建一個名為L...
    sprint閱讀 999評論 0 4
  • 近來有了kindle所以很喜歡看書岂膳,之前因為在高中接觸過東野圭吾的放學后所以決定繼續(xù)未完的閱讀。 已讀清單 《放學...
    衛(wèi)姜閱讀 330評論 0 1
  • 科比退役了磅网,我也很傷心很難過谈截,因為NBA再也沒有我認識的球星了。 開始看籃球看NBA涧偷,還是初中時候的事簸喂,從小一起長...
    昵稱已被占用了閱讀 322評論 0 0