今天和大家一起來學(xué)習(xí)一下iOS序列化和反序列化,有疏忽的地方,還望各位不吝賜教。
一、序列化和反序列化
序列化: 將數(shù)據(jù)結(jié)構(gòu)或?qū)ο筠D(zhuǎn)換成二進(jìn)制串的過程。
反序列化:將在序列化過程中所生成的二進(jìn)制串轉(zhuǎn)換成數(shù)據(jù)結(jié)構(gòu)或者對(duì)象的過程。
在iOS中簡(jiǎn)單粗暴的解釋
- JSON -> OC 反序列化
- OC -> JSON 序列化
二、JSON簡(jiǎn)介
1、什么是JSON
- json是一種輕量級(jí)的數(shù)據(jù)格式
- 服務(wù)器返回給客戶端的數(shù)據(jù),一般都是json或者xml的數(shù)據(jù)
- 80%都是json
2、JSON和OC的對(duì)應(yīng)關(guān)系
- 標(biāo)準(zhǔn)的JSON的 key 必須使用雙引號(hào) iOS必須是雙引號(hào)
- json中的{} 對(duì)應(yīng)OC中的NSDictionary
- json中的[] 對(duì)應(yīng)OC中的NSArray
- json中的雙引號(hào) 對(duì)應(yīng)OC中的NSString
- json中的數(shù)字 對(duì)應(yīng)OC中的NSNumber
3、JSON的解析方案
- 第三方框架:MJExtension(不需要繼承,代碼沒有侵入性)
在選用框架時(shí)注意的問題:(面試福利)
a、侵入性
b、易用性
c、拓展性 - 蘋果原生:NSJSONSerialization(性能最好的)
三、JSON的解析——NSJSONSerialization
1、JSON -> OC 反序列化
/*
* 第一個(gè)參數(shù):json的二進(jìn)制數(shù)據(jù)
* 第二個(gè)參數(shù):
* NSJSONReadingMutableContainers = (1UL << 0),得到OC對(duì)象是可變的
* NSJSONReadingMutableLeaves = (1UL << 1), 字典和數(shù)組中的字符串都是可變的,iOS7以后出現(xiàn)很多問題,一般不會(huì)用到
* NSJSONReadingAllowFragments = (1UL << 2) 既不是字典也不是數(shù)組,則必須使用該枚舉值 如果返回?cái)?shù)據(jù)為@“\"hahahahaha\"”
* 第三個(gè)參數(shù):錯(cuò)誤信息
*/
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
2、OC -> JSON 序列化
/* 注意:并不是所有的OC對(duì)象都可以轉(zhuǎn)化為json 例如字符串
* 頂層必須是NSArray或者NSDictionnary
* 所有的元素必須是 NSString, NSNumber, NSArray, NSDictionary, or NSNull
* 字典中所有的key必須是NSStrings類型的
* NSNumbers 不能是無窮大
*/
// 1、提供轉(zhuǎn)化的OC字典
NSDictionary *dic = @{
@"status":@200,
@"content":@"hello",
@"error":@"enen"
};
// 2、判斷OC對(duì)象是否可以轉(zhuǎn)換為json對(duì)象
BOOL isVaild = [NSJSONSerialization isValidJSONObject:dic];
if (isVaild) {
/*
* 第一個(gè)參數(shù):需要序列化的數(shù)據(jù)
* 第二個(gè)參數(shù):如果添加就輸出排版美觀效果 如果不添加按照默認(rèn)輸出
* NSJSONWritingPrettyPrinted = (1UL << 0)
*/
NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}else{
NSLog(@"該對(duì)象無法轉(zhuǎn)換");
}
3、Plist文件轉(zhuǎn)換為JSON文件
NSArray *arrayM = [NSArray arrayWithContentsOfFile:@"plist文件目錄"];
NSLog(@"%@",arrayM);
// 這里要先進(jìn)行序列化
NSData *data = [NSJSONSerialization dataWithJSONObject:arrayM options:NSJSONWritingPrettyPrinted error:nil];
// 說明:不能直接這樣保存,會(huì)導(dǎo)致輸出不是合法的json數(shù)據(jù),相當(dāng)于一個(gè)xml文件
// [arrayM writeToFile:@"/Users/Urag/Desktop/apps.json" atomically:YES];
[data writeToFile:@"JSON文件目錄" atomically:YES];
四、JSON的解析——MJExtension
這里只是說一下關(guān)于使用MJExtension遇到關(guān)鍵字沖突時(shí)的解決方式。
// 在模型實(shí)現(xiàn)中進(jìn)行關(guān)鍵字的轉(zhuǎn)換 但是侵入性太強(qiáng) 可以到控制器中進(jìn)行設(shè)置
+ (NSDictionary *)mj_replacedKeyFromPropertyName{
return @{
@"ID":@"id",
};
}
// 控制器中進(jìn)行設(shè)置
[model mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
return @{
@"ID":@"id",
};
}];
五、XML簡(jiǎn)介
因?yàn)閄ML現(xiàn)在用的很少,所以上面在iOS中序列化和反序列化說法有點(diǎn)以偏概全了,在這里作補(bǔ)充。。。
一個(gè)常見的XML文檔一般由以下幾部分組成
文檔聲明
元素(Element)
屬性(Attribute)
1、文檔聲明
- <?xml version="1.0" encoding="UTF-8"?>
- 在XML文檔的最前面,必須編寫一個(gè)文檔聲明,用來聲明XML文檔的類型
- 最簡(jiǎn)單的聲明
- <?xml version="1.0"?>
- 用encoding屬性說明文檔的字符編碼
- <?xml version="1.0" encoding="UTF-8"?>
2、元素(Element)
- <error>用戶名不存在</error>
- 一個(gè)元素包括了開始標(biāo)簽和結(jié)束標(biāo)簽
- 擁有內(nèi)容的元素:<video>Fate</video>
- 沒有內(nèi)容的元素:<video/>(簡(jiǎn)寫之后)
- 可以嵌套 但是不能交差嵌套 只能由一個(gè)根元素
元素的注意點(diǎn):
- xml中的所有的空格和換行,都會(huì)當(dāng)做具體內(nèi)容處理
3、屬性
- 一個(gè)元素可以有多個(gè)屬性
- <video name="Fate 第一部" length = "30"/>
- video元素?fù)碛衝ame和length兩個(gè)屬性
- 屬性必須用“” 或者‘’擴(kuò)住
- 實(shí)際上,屬性表示的信息也可以使用子元素來表示,如
<video>
<name>Fate 第一部</name>
<length> 30 </length>
</video>
六、XML的解析方案
1、解析方式:
- DOM 一次性將整個(gè)XML文檔加載進(jìn)入內(nèi)存 比較適合解析小文件
- SAX 從根元素開始。按照順序一個(gè)元素一個(gè)元素往下解析,比較是和解析大文件
2、iOS解析
蘋果原生
- NSXMLParser SAX解析方式,使用簡(jiǎn)單
第三方框架
- libxml2 : 純C語言,默認(rèn)包含子安iOS SDK中,同時(shí)支持DOM和SAX的方式解析
- GDataxml:DOM的方式解析,基于libxml2
XML解析方式的建議 - 小文件: NSXMLParser libxml2
- 大文件:NSXMLParser libxml2 GDataxml
七、XML解析嘗試
1、SAX 解析方式
// 1、創(chuàng)建XML解析器:SAX
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
// 2、設(shè)置代理 <NSXMLParserDelegate>
parser.delegate = self;
// 3、開始解析阻塞的方法
[parser parse];
// 代理方法的介紹
// 1、開始解析時(shí)調(diào)用
- (void)parserDidStartDocument:(NSXMLParser *)parser{
}
// 2、開始解析某個(gè)元素
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict{
NSLog(@"開始解析某個(gè)元素 %@ ===== %@",elementName,attributeDict);
// 使用XML的時(shí)候記得過濾根元素
// 字典轉(zhuǎn)模型在這里實(shí)現(xiàn)就可以了
}
// 3、某個(gè)元素解析完畢
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
NSLog(@"某個(gè)元素解析完畢%@",elementName);
}
// 4、結(jié)束解析時(shí)調(diào)用
- (void)parserDidEndDocument:(NSXMLParser *)parser{
}
2、DOM 解析方式
/*
* 使用GDataXML來進(jìn)行XML的解析 先要進(jìn)行以下配置 而且記得在編譯時(shí)要將其改為MRC環(huán)境 -fno-objc-arc
* libxml includes require that the target Header Search Paths contain
* /usr/include/libxml2
* and Other Linker Flags contain
* -lxml2
*/
// 1、加載XML文檔
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:kNilOptions error:nil];
// 2、拿到根元素,得到所有子孫元素
NSArray * elements = [doc.rootElement elementsForName:@"root"];
// 3、遍歷操作
for (GDataXMLElement *ele in elements) {
// 元素內(nèi)部所有的屬性-->模型
GHModel * model = [[GHModel alloc] init];
model.name = [ele attributeForName:@"name"].stringValue;
// 將模型存入數(shù)組,作為數(shù)據(jù)源使用
[self.data addObject:model];
}
八、控制臺(tái)打印JSON數(shù)據(jù)的中文輸出
/*
* 控制中文輸出核心是重寫系統(tǒng)的description方法
*/
@implementation NSDictionary (log)
// 重寫系統(tǒng)的方法控制輸出
- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level{
NSMutableString *str = [NSMutableString string];
//{}
[str appendString:@"{\n"];
// 拼接key-value
[self enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
[str appendFormat:@"\t%@",key];
[str appendString:@" : "];
[str appendFormat:@"%@,\n",obj];
}];
[str appendString:@"}"];
// 刪除逗號(hào) 從后往前搜索,第一個(gè)符號(hào)的位置
NSRange range = [str rangeOfString:@"," options:NSBackwardsSearch];
if (range.location != NSNotFound) {
[str deleteCharactersInRange:range];
}
return str;
}
@end
@implementation NSArray(log)
// 重寫系統(tǒng)的方法控制輸出
- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level{
NSMutableString *str = [NSMutableString string];
//{}
[str appendString:@"[\n"];
// 拼接obj
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[str appendFormat:@"\t%@,\n",obj];
}];
[str appendString:@"]"];
// 刪除逗號(hào) 從后往前搜索,第一個(gè)符號(hào)的位置 如果找到了就刪除
NSRange range = [str rangeOfString:@"," options:NSBackwardsSearch];
if (range.location != NSNotFound) {
[str deleteCharactersInRange:range];
}
return str;
}