標籤:objective-c json的解析 亂碼 檔案操作
一、什麼是Json?
關於Json的解釋還是看百度百科是怎麼解釋的《百度百科---JSON》,這裡還是比較專業的。首先我們已經知道了我們對象是什麼也知道一些它的基本格式(百度百科有說明)。
我們也來看看我儲存在本地的一個Json檔案,來具體分析一下它的格式。
先選擇左上方的“Outline”模式,我們看見從左至右就是這麼三列,分別是“Type”---類型,“Value”---值和“Name”---名字。有的“Name”前面還有一個三角箭頭,可以點開看看到底是什麼。
裡面是字串形式的資料,再裡面就沒有什麼了。其他的一些就都是形式一樣的。
我們還可以選擇左上方的Text模式查看這個Json文檔。
看見的沒一個Value裡面的內容的形式都是一樣的。
這個Json檔案的結構大致是這樣的:
最外層是一個字典,字典的一個key CATALOG 對應的Vaule CD 是一個數組,這個數組有25個元素,每個元素又是一個字典,字典裡面是六個鍵值對。這個就是這個Json檔案的結構了。
二、Json的解析
Json的解析在Xcode中其實只有簡單的三步。
第一步:把字串形式的連結轉換為url形式;
第二步:使用NSData向伺服器發送請求下載資料,轉化儲存為NSData形式;
第三步:調用系統類別NSJSONSerialization的 + (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;把返回的資料存放區為數組或是字典。為什麼是數組和字典呢?
在Xcode裡面我們可以在NSJSONSerialization類裡面找到這樣一個方法:
/* Returns YES if the given object can be converted to JSON data, NO otherwise. The object must have the following properties:- Top level object is an NSArray or NSDictionary- All objects are NSString, NSNumber, NSArray, NSDictionary, or NSNull- All dictionary keys are NSStrings- NSNumbers are not NaN or infinityOther rules may apply. Calling this method or attempting a conversion are the definitive ways to tell if a given object can be converted to JSON data.*/+ (BOOL)isValidJSONObject:(id)obj;
這個方法是用來判斷一個對象是不是一個Json,如果是就返回YES,否則就返回NO。再來看看四行以 “—”開頭的說明。
第一句:最外層不是數組就是字典
第二句:所有的對象都是NSString, NSNumber, NSArray, NSDictionary, or NSNull 類型的,(還要包括BOOL類型的)
第三句:所有字典的key都是NSString類型的
第四句:所有的NSNumbers不是NaN(還不知道他的解釋)也不是無窮大
這個方法也告訴了我們為什麼Json的最外層是數組或是字典和Json中值的類型。
那麼解析的三步使用代碼怎麼實現呢?其實在代碼中寫簡單一點也就三行代碼。
NSURL * url = [NSURL URLWithString:PATH];//把字串類型是路徑轉換為NSURL 類型的NSData * data = [NSData dataWithContentsOfURL:url];/向從URL中拿資料,NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];//用一個字典接收返回來的資料。
這裡方法裡面的參數為什麼是這樣的?我們可以找到對應的方法的官方的解釋。我們只需要按住鍵盤的“command”鍵,滑鼠移動到方法那裡,點擊就能自動跳轉到相應的方法的申明那裡了。
/* Create a Foundation object from JSON data. Set the NSJSONReadingAllowFragments option if the parser should allow top-level objects that are not an NSArray or NSDictionary. Setting the NSJSONReadingMutableContainers option will make the parser generate mutable NSArrays and NSDictionaries. Setting the NSJSONReadingMutableLeaves option will make the parser generate mutable NSString objects. If an error occurs during the parse, then the error parameter will be set and the result will be nil.The data must be in one of the 5 supported encodings listed in the JSON specification: UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE. The data may or may not have a BOM. The most efficient encoding to use for parsing is UTF-8, so if you have a choice in encoding the data passed to this method, use UTF-8.*/+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
剩下的工作就不難完成了。就是怎麼從返回的字典中拿我們需要的資料了。這些就和Json的解析沒多大關係了。只要理清層級關係,一點一點的拿就行了。
擷取字典裡面的資料我們可以建立一個模型來擷取。在這個Json檔案裡面,每一張專輯都有六個成員,那麼我們就可以以專輯為單位建立模型。然後再把這些模型儲存進一個數組裡面就可以了。
三、建立模型
上面已經說明了這個Json裡面的資料的特點和結構的規律,下面的建立模型就不難了,我們直接看代碼。
①建立一個模型類DataModel,它裡面有六個成員:
@property (nonatomic,copy) NSString * ARTIST; //藝術家@property (nonatomic,copy) NSString * COMPANY; //公司@property (nonatomic,copy) NSString * COUNTRY; //國家@property (nonatomic,copy) NSString * PRICE; //價格@property (nonatomic,copy) NSString * TITLE; //專輯名@property (nonatomic,copy) NSString * YEAR; //年代
我們再在解析這個Json類裡面聲明一個可變數組- (NSArray *)preaseJson;
接下裡就是解析的代碼和模型資料打包了。這段代碼理解起來也不困難。
- (NSArray *)preaseJson{/****************************JSON的解析*************************************/NSURL * url = [NSURL URLWithString:PATH];NSData * data = [NSData dataWithContentsOfURL:url];NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];NSArray * cdArr = dic[@"CATALOG"][@"CD"]; //遍曆CD對應的數組for (NSDictionary * di in cdArr) {DataModel * mo = [[DataModel alloc] init];// mo.ARTIST = di[@"ARTIST"];// mo.COMPANY = di[@"COMPANY"];// mo.COUNTRY = di[@"COUNTRY"];// mo.PRICE = di[@"PRICE"];// mo.TITLE = di[@"TITLE"];// mo.YEAR = di[@"YEAR"];// [_arr addObject:mo];// KVC (鍵 --- 值編碼)//這種方法和上面注釋的方法二選一,使用這種方法就需要在資料模型裡面實現一個列印的方法(這個列印方法可沒有),且上面聲明的成員的名字必須和字典裡面的key名一樣。[mo setValuesForKeysWithDictionary:di];[_arr addObject:mo];}return _arr;}
最後就是列印了
- (void)print{MyJson * myjson = [[MyJson alloc] init];NSArray * array = [myjson preaseJson];int i = 0;for (DataModel * dm in array) {printf("------------- %d -------------\n",++i);printf(" ARTIST : %s\n",[[dm ARTIST] UTF8String]); //藝術家printf(" COMPANY : %s\n",[[dm COMPANY] UTF8String]);//唱片公司printf(" COUNTRY : %s\n",[[dm COUNTRY] UTF8String]);//國家printf(" PRICE : %s\n",[[dm PRICE] UTF8String]); //價格printf(" TITLE : %s\n",[[dm TITLE] UTF8String]); //專輯名printf(" YEAR : %s\n",[[dm YEAR] UTF8String]); //年代// [dm show]; //這個show方法也是把上面的6行printf封裝一下}}+ (void)test{MyJson * js = [[MyJson alloc] init];[js print];}最後在main函數裡面就只有一條語句:[MyJson test];
就這樣資料基本解析出來了。最後的列印結果:一共25個。
如果我們想把資料儲存進一個txt文檔,就需要檔案操作了。前面已經介紹了一種檔案操作的方式,現在再來介紹一種檔案操作的方式。
四、NSFileManager 類
其實這裡的檔案的操作也不難,代碼量也不大。
+ (void)dataPacket{MyJson * json = [[MyJson alloc] init];NSArray * dataArr = [json preaseJson]; // 數組dataArr中儲存 解析後的資料模型NSMutableString * str = [[NSMutableString alloc] init];//建立一個可變字串NSFileManager * myFile = [NSFileManager defaultManager];int i = 0;for (DataModel * md in dataArr) {[str appendFormat:@"%d %@",++i,@"-----------------------------\n"];[str appendFormat:@"%@%@%@",@" ARTIST : ",md.ARTIST,@"\n"];[str appendFormat:@"%@%@%@",@" COMPANY : ",md.COMPANY,@"\n"];[str appendFormat:@"%@%@%@",@" COUNTRY : ",md.COUNTRY,@"\n"];[str appendFormat:@"%@%@%@",@" PRICE : ",md.PRICE,@"\n"];[str appendFormat:@"%@%@%@",@" TITLE : ",md.TITLE,@"\n"];[str appendFormat:@"%@%@%@",@" YEAR : ",md.YEAR,@"\n"];}NSData * data = [str dataUsingEncoding:NSUTF8StringEncoding];[myFile createFileAtPath:SAVEPATH contents:data attributes:nil];}最後幾句中的SAVEPATH就是儲存路徑,需要帶上檔案格式的,就像你看一個檔案的屬性裡面顯示的那樣,如:/user/Desktop/123.txt。
最後我們開啟看看裡面儲存的是Xcode列印出來的形式也是一樣的。我們也需在main加上一句代碼,代碼我就不寫了。
關於KVC 鍵值編碼還不是很會使用,以後熟練了再寫出來。
最後上傳一張圖片關於使用蘋果內建瀏覽器開啟json文檔亂碼的問題是怎麼解決的。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
【IOS開發之Objective-C】Json的解析 一