iOS XML/JSON數(shù)據(jù)交換格式

一. XML數(shù)據(jù)交換格式

XML數(shù)據(jù)交換格式是一種自描述的數(shù)據(jù)交互格式捂襟,雖然XML數(shù)據(jù)格式不如JSON "輕便",但也是非常重要的數(shù)據(jù)交互格式趴酣。

  • XML文檔的基本結(jié)構(gòu)

XML文檔結(jié)構(gòu)要遵守一定的格式規(guī)范梨树。XML雖然形式上與HTML很相似,但是它有著嚴(yán)格的語法規(guī)則,只有嚴(yán)格按照規(guī)范編寫的XML文檔才是有效的文檔,稱為“格式良好"(well-formed)的XML文檔
先來看幾張圖


C739220F-9A98-4781-83F6-46E24219AA2A.png

B2BDE67B-B499-485F-8245-FDA618073445.png

785C1FF7-BC43-4E8A-A477-7D853409434D.png

XML文檔的基本架構(gòu),可以分為下列幾個(gè)部分:

1 . 聲明:如圖3-3所示的<?xml version="1. 0" encoding="UTF-8"? > 就是XML文件的聲明,它定義XML文件的版本和使用的字符集,此例為1.0版岖寞,使用中文UTF-8 字符抡四。

2 . 根元素:如圖3-3所示的note是XML文件的根元素,<note>是根元素的開始標(biāo)簽,</note>是根元素的結(jié)束標(biāo)簽根元素只有一個(gè),開始和結(jié)束標(biāo)簽必須一致指巡。

3 . 子元素:如圖3-3所示的to淑履、content、from和date是根元素note的子元素藻雪。所有元素都要有結(jié)束標(biāo)簽,開始和結(jié)束標(biāo)簽必須一致秘噪。如果開始標(biāo)簽和結(jié)束標(biāo)簽之間沒有內(nèi)容,可以 寫成<from/> ,稱為“空標(biāo)簽”。

4 . 屬性:圖3-4所示,是具有屬性的XML文檔阔涉。圖3-4的XML文檔中沒有屬性,屬性是定義在開始標(biāo)簽中的,在開始標(biāo)簽<Note id="1">中的id="1"是Note元素的一個(gè)屬性,id是屬性名缆娃,1是屬性值,屬性值必須放置在雙引號(hào)或單
引號(hào)之間。一個(gè)元素不能有多個(gè)相同名字的屬性瑰排。

5 . 命名空間:**用于 **一個(gè)XML文檔中提供名字唯一的元素和屬性 **贯要。例如: 在一個(gè)學(xué)籍信息的XML 文檔中需要引用到教師和學(xué)生,他們都有一個(gè)子元素id,這時(shí)候直接引用id元素會(huì)造成名稱沖突椭住。但是如果將兩個(gè)id元素放到不同的命名空間中就會(huì)解決這個(gè)問題崇渗。圖3 -5 中的“xmIns:”開頭的內(nèi)容,xmIns: xsi="http://www.w3.org/2001/XMLSchema " 等都屬于命名空間京郑。

6. ** 限定名由命名空間引出的概念, 定義了元素和屬性的合法標(biāo)識(shí)
宅广。限定名通常在XML 文檔中用作特定元素或?qū)傩缘囊?/strong>。圖3 -5 中的標(biāo)簽<soap:Body>就是合法的限定名些举,前綴soap是由命名空間定義的跟狱。

  • XML文檔的解析與框架性能

對于XML文檔操作包括了 “讀”與“寫”讀人 XML 文檔 并 分析 的過程稱為 “解析”XML 文檔; 事實(shí)上,在使用XML 開發(fā)過程中户魏,“解析”XML 文檔工作占很大的比重驶臊。

讀寫XML 文檔,目前流行的有兩種模式: SAXDOM

  1. SAX 是一種基于事件驅(qū)動(dòng)的解析模式叼丑。并不需要讀入整個(gè)文檔,文檔的讀入過程也就是SAX的解析過程关翎。解析XML的時(shí)候,程序從上到下讀取XML文檔,簡單地說就是對XML文檔進(jìn)行順序掃描,當(dāng)掃描到 文檔 的 開始 與 結(jié)束 鸠信,元素(element)的 開始 與 結(jié)束 時(shí)纵寝,就會(huì)觸發(fā)相應(yīng)的事件處理 函數(shù),由事件處理函數(shù)做相應(yīng)的動(dòng)作星立,處理完后繼續(xù)掃描爽茴,直到文檔結(jié)束,則解析完畢绰垂。但是這種解析XML 文件有一個(gè)弊端就是只能讀取XML文檔,不能寫人XML 文檔闹啦。它的優(yōu)點(diǎn)是解析速度快,iOS重點(diǎn)推薦使用SAX模式解析,而且對內(nèi)存的要求通常會(huì)比較低辕坝,特別是當(dāng)開發(fā)人員只需要處理文檔中所包含的部分?jǐn)?shù)據(jù)時(shí)窍奋,SAX這種擴(kuò)展功能得到了更好的體現(xiàn)。

  2. DOM是一種基于文檔驅(qū)動(dòng)的解析模式 。DOM 需要讀入整個(gè)XML文檔琳袄,DOM是將XML 文檔作為一棵樹狀結(jié)構(gòu)進(jìn)行分析,提供獲取節(jié)點(diǎn)的內(nèi)容,以及相關(guān)屬性江场,或者新增、刪除和修改節(jié)點(diǎn)的內(nèi)容.DOM將XML文件的元素視為樹狀結(jié)構(gòu)的節(jié)點(diǎn)窖逗,一次性讀入到內(nèi)存中址否。如果文檔比較大,解析速度就會(huì)比較慢碎紊,所以對性能和內(nèi)存的要求比較高佑附。但是DOM模式有一點(diǎn)是SAX無法取代的,就是DOM可以修改XML 文檔仗考。

延伸:SAX和DOM的區(qū)別

  1. SAX處理的優(yōu)點(diǎn)非常類似于流媒體的優(yōu)點(diǎn)音同。分析能夠立即開始,而不是等待所有的數(shù)據(jù)被處理秃嗜。而且由于應(yīng)用程序只是在讀取數(shù)據(jù)時(shí)檢查數(shù)據(jù)对人,因此不需要將數(shù)據(jù)存儲(chǔ)在內(nèi)存中歧寺。這對于大型文檔來說是個(gè)巨大的優(yōu)點(diǎn)葫督。事實(shí)上應(yīng)用程序甚至不必解析整個(gè)文檔妆绞;他可以在某個(gè)條件得到滿足時(shí)停止解析。一般來說必搞,SAX還比它的替代者DOM快許多必指。另一方面,由于應(yīng)用程序沒有以任何方式存儲(chǔ)數(shù)據(jù)恕洲,使用SAX還比它的替代者DOM快許多塔橡。另一方面,由于應(yīng)用程序沒有以任何方式存儲(chǔ)數(shù)據(jù)研侣,使用SAX來更改數(shù)據(jù)或在數(shù)據(jù)流中往后移是不可能的。
  2. DOM以及廣義的基于樹的處理有幾個(gè)優(yōu)點(diǎn)首先由于樹在內(nèi)存中是持久的炮捧,因此可以修改它以便應(yīng)用程序能對數(shù)據(jù)和結(jié)構(gòu)做出更改庶诡。它還可以在任何時(shí)候在樹中上下導(dǎo)航,而不像SAX那樣一次性的處理咆课。DOM使用起來簡單的多末誓。
  3. 選擇DOM還是SAX,這取決于以下幾個(gè)因素:
    應(yīng)用程序的目的书蚪;數(shù)據(jù)容量喇澡。
  4. 對速度的需要:SAX實(shí)現(xiàn)通常要比DOM實(shí)現(xiàn)更快。

iOS SDK提供了兩個(gè)的XML框架:
1. NSXML,基于Objective-C語言SAX解析框架殊校,它是iOS SDK默認(rèn)的XML解析框架,它不支持DOM模式晴玖。
2. libxml2,基于C語言的第三方(http://xmlsoft.org/)提供的SAX解析框架,被蘋果整合在iOSSDK中,它支持SAX和DOM模式,所以使用起來相對不太方便,但它同時(shí)支持DOM和SAX解析,尤其是它的SAX解析方式很酷,可以邊讀邊解析,非常適用于從網(wǎng)上下載一個(gè)很大的XML文件,可極大提供解析效率呕屎。

此外,iOS中解析XML還有很多第三方框架可以采用,這些框架主要有:
1. TBXML,是輕量級(jí)的DOM模式解析庫,有很好的性能和低內(nèi)存占用,不過它不對XML格式進(jìn)行校驗(yàn),不支持XPath,并且只支持解析,不支持對XML進(jìn)行修改;
2. TouchXML,基于DOM模式解析庫,支持XPath,只支持解析,不支持XML的修改;
3. KissXML,基于DOM模式解析庫,它是基于TouchXML,主要的不同是可以寫如XML文檔;
4. TinyXML,基于C++語言的DOM模式解析庫,支持對XML的讀取和修改,不直接支持XPath,需要借助TinyXPath才可以支持XPath;
5. GDataXML,基于DOM模式解析庫,是由Google開發(fā),支持讀取和修改XML文檔,支持XPath方式查詢让簿。

這么多的框架我們選擇哪一個(gè)呢?解析性能是選擇的主要指標(biāo),我自己沒測試過秀睛,別人編寫了一個(gè)測試程序來測試這些框架測試程序采用GHUnit單元測試框架尔当。
測試文件是MyNotes應(yīng)用中的XML文檔,我準(zhǔn)備了10000條Note數(shù)據(jù)的XML 文檔,保存后文件大小達(dá)到了1.2M。在第4代iPod touch設(shè)備上運(yùn)行GHUnit測試程序,結(jié)果如圖3-6所示蹂安。

D66CC264-19A2-4A1E-99E7-32B9F1293961.png

從圖3-6中可以看出TBXML框架花費(fèi)時(shí)間最短椭迎,TouchXML框架花費(fèi)時(shí)間最長。當(dāng)然速度并不能說明一切,還要看看內(nèi)存占用這個(gè)指標(biāo)田盈。上面的測試程序 還可以進(jìn)行內(nèi)存占用峰值執(zhí)行后駐留內(nèi)存比較,內(nèi)存占用峰值是衡量解析過程中占用的最大內(nèi)存畜号,它會(huì)影響應(yīng)用程序當(dāng)前運(yùn)行狀況,影響是暫時(shí)的。而執(zhí)行后駐留內(nèi)存衡量解析完成之后內(nèi)存的駐留情況缠黍,它會(huì)影響應(yīng)用程序運(yùn)行后的狀況,影響是長期的弄兜。

使用Xcode自帶的Instrument檢查工具來檢查內(nèi)存占用情況圖3-7所示是Instrument工具運(yùn)行的結(jié)果,我們只需要查看Allocations中的最大值就是內(nèi)存占用峰值了(圖中所示是9.12MB),趨于平穩(wěn)后的內(nèi)存就是駐留內(nèi)存占用了(圖中為2.96MB)瓷式。

FBE86D90-9420-4022-B8AE-5BF70846068B.png

4CE9E810-F1E8-4A06-A922-9EC4A0517EC0.png

在圖3-8中有內(nèi)存占用峰值替饿、執(zhí)行后駐留內(nèi)存解析時(shí)間3個(gè)指標(biāo)的比較。TouchXML應(yīng)該是最差的了,TBXML雖然是DOM解析模式,但解析速度是最快的,但是內(nèi)存占用峰值比較高,駐留內(nèi)存較低贸典。而KissXML和TinyXML也是一個(gè)不錯(cuò)的選擇,還有iOS SDK中的NSXML在速度和內(nèi)存占用都比較優(yōu)秀,如果這幾個(gè)指標(biāo)都想兼顧情況下NSXML是不錯(cuò)的選擇视卢。

我們從性能的3個(gè)主要指標(biāo)分析了這7個(gè)XML解析框架。當(dāng)然這是從用戶的角度出發(fā),如果從開發(fā)人員的角度出發(fā),除了上面的兩個(gè)指標(biāo)外,還要關(guān)注開發(fā)是否方便,以及對于XML文檔的讀寫是否支持等廊驼。它們的對比如表3-1所述据过。

6BECFB70-3550-40E0-91A9-36F35ECDA166.png

iOS下開發(fā)一般使用Objctive-C,因此從開發(fā)人員的學(xué)習(xí)曲線角度看,支持Objctive-C的框架是比較s容易使用的妒挎。但是如果讀者具有C或C++基礎(chǔ)的話,這就不是問題了绳锅。XPath是一個(gè)不錯(cuò)的技術(shù),用于XML的查詢。如果把XML文檔看做數(shù)據(jù)庫,那么XPath就相當(dāng)于SQL查詢語言酝掩。因此能夠支持XPath的框架,開發(fā)起來比較方便,這個(gè)前提是你對于XPath技術(shù)比較熟悉鳞芙。前面分析的都是讀取XML文檔,如果需要寫入XML文檔就需要注意了。

  1. 如果是讀取很小的XML文檔期虾,性能基本上沒有什么差別原朝,不過從調(diào)用的方便性來說,建議使用TouchXML镶苞、KissXML或GDataXML喳坠。
  2. 如果是需要讀取和修改XML文檔,建議使用KissXMLGDataXML茂蚓。
  3. 如果需要讀取非常大的XML文檔壕鹉,則建議使用libxml2TBXML剃幌。
  4. 如果你不想去調(diào)用第三方類庫,那么使用NSXML也可以御板。
  • 實(shí)例 : MyNotes 應(yīng)用 XML

其他第三方XML解析框架,可以百度一下

下面通過一個(gè)實(shí)例介紹NSXML框架解析XML的過程,現(xiàn)在有一個(gè)記錄我的備忘錄信息的Notes. xml文件,內(nèi)容如下:

<?xml version="1.0" encoding="UTF-8"?>
<Notes>
  <Note id="1">
    <CDate>2012-12-21</CDate>
    <Content>早上8點(diǎn)鐘到公司</Content>
    <UserID>tony</UserID>
  </Note>
  <Note id="2">
    <CDate>2012-12-22</CDate>
    <Content>發(fā)布iOSBook1</Content>
    <UserID>tony</UserID>
  </Note>
  <Note id="3">
    <CDate>2012-12-23</CDate>
    <Content>發(fā)布iOSBook2</Content>
    <UserID>tony</UserID>
  </Note>
  <Note id="4">
    <CDate>2012-12-24</CDate>
    <Content>發(fā)布iOSBook3</Content>
    <UserID>tony</UserID>
  </Note>
  <Note id="5">
    <CDate>2012-12-25</CDate>
    <Content>發(fā)布2016奧運(yùn)會(huì)應(yīng)用iPhone版本</Content>
    <UserID>tony</UserID>
  </Note>
  <Note id="6">
    <CDate>2012-12-26</CDate>
    <Content>發(fā)布2016奧運(yùn)會(huì)應(yīng)用iPad版本</Content>
    <UserID>tony</UserID>
  </Note>
</Notes>

文檔中的根元素是Notes,其中有很多子元素Note,每個(gè)Note 元素都有一個(gè)id 屬性(表示“備忘錄”的序號(hào)),以及3 個(gè)子元素CDate (表示“備忘錄”的日期).Content(表示“備忘錄”的內(nèi)容)和UserID(表示“備忘錄”的創(chuàng)建人ID)锥忿。

![9305943C-B8B0-451F-ADA1-1CBAEE02B7D1.png](https://upload-images.jianshu.io/upload_images/11711200-1c7140a4ff8f0989.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

應(yīng)用運(yùn)行畫面如圖3 9所示。其中的數(shù)據(jù)來源于本地資源文件中的Notes.xml 文件怠肋。我們需要使用NSXMLParser 框架解析XML 文檔,并將數(shù)據(jù)放置于畫面表視圖中敬鬓。

1. 使用NSXML
NSXML是iOSSDK 自帶的,也是蘋果默認(rèn)解析框架,采用SAX模式解析。它是SAX解析模式的代表笙各。NSXML框架中的核心NSXMLParser 和它的委托NSXMLParserDelegate钉答。主要的解析工作是在委托協(xié)議NSXMLParserDelegate 的實(shí)現(xiàn)類中完成的,委托中定義了很多回調(diào)方法,在SAX解析器從上圖3-9 MyNotes應(yīng)用設(shè)計(jì)到下遍歷XMI文檔的過程中,遇到開始標(biāo)簽杈抢、結(jié)束標(biāo)簽数尿、文檔 原型草圖開始、文檔結(jié)束和字符串就會(huì)觸發(fā)這些方法惶楼。這些方法有很多右蹦,我們列出5 個(gè)常用的:
(1) parserDidStartDocumet,在文檔開始的時(shí)候觸發(fā);
(2) parser:didStartElement :namespaceURI: qualifiedName: attributes,遇到一個(gè)開始標(biāo)簽時(shí)觸發(fā),其中namespaceURI 部分是命名空間,qualifiedName 是:限定名,attributes 是字典類型的屬性集合;
(3) parser:foundCharacters,遇到字符串時(shí)觸發(fā);
(4) parser:didEndElement:namespaceURIqualifiedName,遇到結(jié)東標(biāo)簽時(shí)出發(fā);
(5) parserDidEndDocument,遇到文檔結(jié)束時(shí)觸發(fā)歼捐。

其中前5個(gè)方法都是按照解析文檔的順序觸發(fā)的,理解它們先后順序很重要,可以通過圖3 -10所示的UML時(shí)序圖了解它們的觸發(fā)順序何陆。

9305943C-B8B0-451F-ADA1-1CBAEE02B7D1.png

就同一個(gè)元素而言觸發(fā)順序是按照圖3-10所示進(jìn)行的,在整個(gè)解析過程中它們的觸發(fā)次數(shù)是: 1方法和5 方法為一對,都只觸發(fā)1次豹储,2 方法和4 方法為一對贷盲,都觸發(fā)多次,3方法是在2 方法和4 方法之間觸發(fā)它也會(huì)多次觸發(fā),觸發(fā)的字符包括了換行符和回車符等特殊字符串,在編程時(shí)需要注意

編寫了一個(gè)專門解析類NotesXMLParser,
NotesXMLParser.h 文件代碼如下:

#import <Foundation/Foundation.h>

@interface NotesXMLParser : NSObject <NSXMLParserDelegate>

//解析出的數(shù)據(jù)內(nèi)部是字典類型
@property (strong,nonatomic) NSMutableArray *notes;
//當(dāng)前標(biāo)簽的名字
@property (strong,nonatomic) NSString *currentTagName;

//開始解析
-(void)start;

@end

NotesXMLParser 實(shí)現(xiàn)NSXMLParserDelegate 協(xié)議剥扣,還定義了currentTagName 屬性的目的是在圖3 -10所示的2 方法到4 方法執(zhí)行期間臨時(shí)存儲(chǔ)正在解析的元素名,在3 方法(parser:foundCharacter )觸發(fā)時(shí)巩剖,能夠知道目前解析器處于哪個(gè)元素之中。
NotesXMLParser.m 中的start 方法代碼如下

-(void)start
{
    NSString* path = [[NSBundle mainBundle] pathForResource:@"Notes" ofType:@"xml"];
    
    NSURL *url = [NSURL fileURLWithPath:path];
    //開始解析XML
    NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
    parser.delegate = self;
    [parser parse];
    NSLog(@"解析完成...");
}

NSXMLParser是解析類,它有 3 個(gè)構(gòu)造方法:
1.initWithContentsOfURL,可以使用URL 對象創(chuàng)建解析對象,本例中采用的是該方法,先從資源文件中加載獲得URI對象,再使用URL對象構(gòu)建解析對象;

  1. initWithData,可以使用NSData 創(chuàng)建解析對象;
  2. initWithStream,可以使用IO 流對象創(chuàng)建解析對象钠怯。
    解析對象創(chuàng)建好后需要指定委托屬性delegate為self,然后發(fā)送parse消息,開始解析文檔佳魔。

NotesXMLParser.m 中 的方法代碼如下:

/**
 文檔開始的時(shí)候觸發(fā)
 
 只在解析開始時(shí) 觸發(fā)一次 ,因此可以在這個(gè)方法中 初始化解析過程中用到的一些 成員變量
 
 @param parser 解析對象
 */
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
    _notes = [NSMutableArray new];
}


/**
 文檔出錯(cuò)的時(shí)候觸發(fā)

 @param parser 解析對象
 @param parseError 解析錯(cuò)誤
 */
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
    NSLog(@"%@",parseError);
}


/**
 遇到一個(gè)開始標(biāo)簽時(shí)候觸發(fā)

 @param parser 解析對象
 @param elementName 表示正在解析的元素的名字
 @param namespaceURI  部分是命名空間
 @param qualifiedName 限定名
 @param attributeDict 字典類型的屬性集合
 */

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qualifiedName
    attributes:(NSDictionary *)attributeDict
{
    _currentTagName = elementName;//需要把elementName參數(shù)賦值給成員變量_currentTagName

    if ([_currentTagName isEqualToString:@"Note"]) {
        NSString *_id = [attributeDict objectForKey:@"id"];//從字典中取出id屬性
        NSMutableDictionary *dict = [NSMutableDictionary new];//實(shí)例化一個(gè)可變字典對象,用來存放解析出來的Note元素?cái)?shù)據(jù),成功解析之后字典中應(yīng)該有4對數(shù)據(jù),即id、CDate晦炊、Content和UserID
        [dict setObject:_id forKey:@"id"];//把id放人可變字典中
        [_notes addObject:dict];//把可變字典放人到可變數(shù)組集合_ notes 變量中
    }
    
}

/**
 遇到字符串時(shí)候觸發(fā)鞠鲜,該方法是解析元素文本內(nèi)容主要場所

 @param parser 解析對象
 @param string 字符串
 
 ,由于換行符和回車符等特殊字符也會(huì)觸發(fā)該方法,因此在第①行是用剔除換行符和回車符,其中stringByTrimmingCharactersInSet:方法是剔除字符方法,[NSCharacterSet whitespaceAndNewlineCharacterSet]指定字符集為換行符和回車符。
 */
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    //替換回車符和空格
    /*
     由于換行符和回車符等特殊字符也會(huì)觸發(fā)該方法,因此在第①行是用剔除換行符和回車符,
     其中stringByTrimmingCharactersInSet:方法是剔除字符方法,[NSCharacterSet whitespaceAndNewlineCharacterSet]指定字符集為換行符和回車符刽锤。
     */
    string =[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    if ([string isEqualToString:@""]) {
        return;
    }
    
    NSMutableDictionary *dict = [_notes lastObject];
    
    if ([_currentTagName isEqualToString:@"CDate"] && dict) {
        [dict setObject:string forKey:@"CDate"];
    }
    
    if ([_currentTagName isEqualToString:@"Content"] && dict) {
        [dict setObject:string forKey:@"Content"];
    }
    
    if ([_currentTagName isEqualToString:@"UserID"] && dict) {
        [dict setObject:string forKey:@"UserID"];
    }
}

/**
 遇到結(jié)束標(biāo)簽時(shí)候出發(fā)
 
 在該方法中主要是清理剛剛解析完成的元素產(chǎn)生的影響镊尺,以便于不影響接下來的解析
 
 @param parser 解析對象
 @param elementName 表示正在解析的元素的名字
 @param namespaceURI 部分命名空間
 @param qName 限定名
 */
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qName;
{
    self.currentTagName = nil;//在該方法中主要是清理剛剛解析完成的元素產(chǎn)生的影響朦佩,以便于不影響接下來的解析
}



/**
 遇到文檔結(jié)束時(shí)候觸發(fā)
 
 該方法就意味著解析完成,需要清理一些成員變量并思,同時(shí)要將數(shù)據(jù)返回給表示層
 (表視圖控制器),我們使用了通知機(jī)制將數(shù)據(jù)通過廣播通知投送回表示層。

 @param parser 解析對象
 */
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"reloadViewNotification" object:self.notes userInfo:nil];
    self.notes = nil;
} 

表示層的主要代碼

- (void)viewDidLoad
{
    [super viewDidLoad];
   
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(reloadView:)
                                                 name:@"reloadViewNotification"
                                               object:nil];

    NotesTBXMLParser *parser = [NotesTBXMLParser new];
    //開始解析
    [parser start];

}

#pragma mark - 處理通知
-(void)reloadView:(NSNotification*)notification
{
    NSMutableArray *resList = [notification object];
    self.listData  = resList;
    [self.tableView reloadData];
}

二. JSON數(shù)據(jù)交換格式

JSON數(shù)據(jù)交換格式是一種輕量級(jí)的數(shù)據(jù)交換格式语稠。所謂的輕量級(jí)與XML文檔結(jié)構(gòu)相比而言宋彼,描述項(xiàng)目字符少弄砍,所以描述相同的數(shù)據(jù)的所需字符個(gè)數(shù)要少,那么傳輸?shù)乃俣染蜁?huì)提高而流量也會(huì)減少输涕。
由于

  • JSON的文檔結(jié)構(gòu)

構(gòu)成JSON 文檔兩種結(jié)構(gòu): 對象數(shù)組音婶。

對象“名稱-值”對 集合,它類似于Objective-C 中的字典類型莱坎。
數(shù)組一連串元素的集合衣式。

對象是一個(gè)無序的“名稱/值”對集合,一個(gè)對象以“{”(左括號(hào))開始檐什,“}”(右括號(hào))結(jié)束碴卧。每個(gè)“名稱”后跟一個(gè)“:”(冒號(hào)),“名稱-值”對之間使用“,”(逗號(hào))分隔,JSON 對象語法表如圖3-11所示。

810BF451-5A6A-4B2D-A66F-AF6B562D53AF.png

下面是一個(gè)JSON的對象例子:

{
  "name" :"a.htm",
  "size" :345,
  "saved" :true
}

數(shù)組是一個(gè)值的有序集合乃正,一個(gè)數(shù)組以“[”(左中括號(hào))開始住册,“]”(右中括號(hào))結(jié)束,值之間使用“,”(逗號(hào))分隔,JSON數(shù)組語法表如圖3-12所示。

28360AF2-DB3D-4F3B-814C-CBB9D83A9375.png

下面是一個(gè)JSON的數(shù)組例子:

["text","html","css"]

數(shù)組中值可以是雙引號(hào)括起來的字符串瓮具、數(shù)值荧飞、truefalse名党、null叹阔、對象或者數(shù)組,而且這些結(jié)構(gòu)可以嵌套,數(shù)組中值的JSON語法結(jié)構(gòu)圖3-13所示。

4C3C9220-28A8-4E09-A342-EFD9DA60684C.png

  • JSON的文檔的解析與框架性能

數(shù)據(jù)寫成JSON結(jié)構(gòu)過程稱為“編碼”過程,即寫入過程兑巾。把數(shù)據(jù)從JSON文檔中讀取處理的過程稱為“解碼”過程条获,即解析和讀取過程

由于JSON基本比較成熟,在iOS平臺(tái)上也會(huì)有很多框架可以進(jìn)行JSON的編碼/解碼蒋歌。這些框架包括:

  1. SBJson是比較老的JSON編碼/解碼框架帅掘,原名是json-framework,這個(gè)框架現(xiàn)在更新仍然很頻繁,支持ARC。
  2. TouchJSON也是比較老的JSON編碼/解碼框架堂油,支持ARC和MRC
  3. YAJL是比較優(yōu)秀的JSON框架,它基于SBJson,里面進(jìn)行了優(yōu)化,底層API使用C編寫,上層API是Objective-C編寫,使用者可以有多種不同的選擇修档。它不支持ARC。
  4. JSONKit 是更為優(yōu)秀的JSON框架府框,它的代碼很小,但是解碼速度很快,不支持ARC,源碼下載地址https://github.com/johnezang/JSONKit吱窝。
  5. NextiveJson 也是非常優(yōu)秀的JSON框架,它與JSONKit性能差不多,但是在開源社區(qū)中沒有JSONKit 知名度高,不支持ARC,源碼下載地址https://github.com/nextive/NextiveJson
  6. NSJSONSerialization 是iOS5 之后蘋果提供的API,它是目前非常優(yōu)秀的JSON編碼/解碼框架迫靖,支持ARC,iOS5之后的SDK就已經(jīng)包含了,不需要額外的安裝和配置,這是它的另外一個(gè)優(yōu)點(diǎn)院峡。但是如果你的應(yīng)用要兼容iOS5 之前的版本這個(gè)框架不能使用。

為了解析這些框架的性能系宜,我們可以參照XML為了解析這些框架的性能照激,我們可以參照XML實(shí)現(xiàn)MyNotes 應(yīng)用,我準(zhǔn)備了10000 條Note 數(shù)據(jù)的JSON 文檔,保存后文件大小達(dá)到了700KB,而同樣信
息的XML文檔是1.2M,這也印證JSON是輕量級(jí)的數(shù)據(jù)交互格式。同樣是在第4 代iPod touch設(shè)備上運(yùn)行GHUnit測試程序盹牧,結(jié)果如圖3-14 所示俩垃。


11D37FAC-C3DC-406B-A7E7-F65755195113.png

從圖中可以看出蘋果提供的NSJSONSerialization 框架花費(fèi)時(shí)間最短,TouchJSON 和SBJson框架花費(fèi)時(shí)間基本上最長励幼。我們再來看看內(nèi)存占用指標(biāo),使用Instrument 檢查工具來檢查內(nèi)存占用情況,最后將內(nèi)存占用峰值口柳、駐留內(nèi)存占用和上面的解碼花費(fèi)時(shí)間苹粟,一起繪制成如圖3-15所示的圖表。

D0C12407-5FAC-4213-903E-B44BE4EC71B9.png

在該圖表中有內(nèi)存占用峰值跃闹、執(zhí)行后駐留內(nèi)存解析時(shí)間3 個(gè)指標(biāo)的比較嵌削。TouchJSON和SBJson應(yīng)該是很差的,事實(shí)上SBJson 在iOS 5 之前的用戶很多。NSJSONSerialization 是解
碼速度最快的,內(nèi)存占用峰值是最低的,可見NSJSONSerializatio是一個(gè)非常優(yōu)秀的JSON解碼框架
望艺,但是它的執(zhí)行后駐留內(nèi)存卻比Nextivelson要高, NextiveJson解碼速度也是比較快的掷贾,內(nèi)存峰值要比NSJSONSerialization略高一些

事實(shí)上,執(zhí)行后駐留內(nèi)存多少對于應(yīng)用程序的影響是比較大的荣茫,而且是長期的影響,這些內(nèi)存不經(jīng)過特殊釋放就會(huì)一直保持在那里想帅。它們將伴隨整個(gè)應(yīng)用程序生命周期,直到應(yīng)用被終止才被釋放,對于整個(gè)設(shè)備都會(huì)有比較大的影響啡莉。
因此,綜合考慮,如果需要考慮兼容iOS5之前的版本,NextiveJson和JSONKit都是不錯(cuò)的選擇港准。它們都不支持ARC,使用起來有點(diǎn)麻煩,需要安裝和配置到工程環(huán)境中。

  • 實(shí)例: MyNotes應(yīng)用JSON解碼

上一節(jié)從性能的3個(gè)主要指標(biāo)分析了這6個(gè)JSON編碼/解碼框架咧欣。這一節(jié)介紹一下NSJSONSerialization如何實(shí)現(xiàn)JSON的解碼的浅缸。實(shí)例還是采用MyNote應(yīng)用,重新設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)為JSON格式,備忘錄信息的Notes. json文件,它的內(nèi)容如下:

{"ResultCode":0,
  "Record":[
    {"ID":"1","CDate":"2012-12-23","Content":"發(fā)布iOSBook0","UserID":"tony"},
    {"ID":"2","CDate":"2012-12-24","Content":"發(fā)布iOSBook1","UserID":"tony"},
    {"ID":"3","CDate":"2012-12-25","Content":"發(fā)布iOSBook2","UserID":"tony"},
    {"ID":"4","CDate":"2012-12-26","Content":"發(fā)布iOSBook3","UserID":"tony"},
    {"ID":"5","CDate":"2012-12-27","Content":"發(fā)布iOSBook4","UserID":"tony"}
   ]
}

注意:在上面介紹的6個(gè)框架中對于JSON文檔的結(jié)構(gòu)要求比較嚴(yán)格魄咕,每個(gè)JSON數(shù)據(jù)項(xiàng)目“名稱”必須使用雙引號(hào)括起來,不能使用單引號(hào)或沒有引號(hào)衩椒,如下代碼文檔中“名稱”省略雙引號(hào),該文檔在iOS平臺(tái)解析時(shí)會(huì)出現(xiàn)異常,而在Java等其他平臺(tái)就沒有這些限制,也不會(huì)出現(xiàn)異常,而我們的JSON數(shù)據(jù)很多情況下編碼和解碼并非是一種語言的哮兰。

{ResultCode:0,
  Record:[
    {ID:'1',CDate:'2012-12-23',Content:'發(fā)布iOSBook0',UserID:'tony'},
    {ID:'2',CDate:'2012-12-24',Content:'發(fā)布iOSBook1',UserID:'tony'}
   ]
}

JSON的解碼過程就是將字符串,分析之后讀入到一個(gè)集合對象中,這個(gè)集合對象的結(jié)構(gòu)可能是數(shù)組毛萌,也可能是字典。Notes. json解碼之后整個(gè)的結(jié)構(gòu)是一個(gè)字典,這個(gè)字典有兩個(gè)“名字值”,與Record名字對應(yīng)的值是一個(gè)數(shù)組,而數(shù)組中的每一個(gè)元素又是一個(gè)字典對象喝滞。取得其中的內(nèi)容也相似“剝洋蔥皮”阁将。

使用NSJSONSerialization實(shí)現(xiàn)解碼過程是非常簡單的,因?yàn)楹唵?所以沒有必要再為解碼單獨(dú)創(chuàng)建一個(gè)類,直接使用就可以了。

- (void)viewDidLoad
{

    NSString* path = [[NSBundle mainBundle] pathForResource:@"Notes" ofType:@"json"];
    NSData *jsonData = [[NSData alloc] initWithContentsOfFile:path];
    NSError *error;

   /*
     使用NSJSONSerialization的類方法JSONObjectWithData: options; error;進(jìn)行解碼其中options參數(shù)指定了解析JSON模式,它是枚舉類型NSJSONReadingOptions中定義了三個(gè)常量:
     (1) NSJSONReadingMutableContainers,指定解析返回的是可變的數(shù)組或字典右遭,如果以后需要修改結(jié)果,這個(gè)常量是合適的選擇;
     (2) NSJSONReadingMutableLeaves,指定葉節(jié)點(diǎn)是可變字符串;
     (3) NSJSONReadingAllowFragments,指定頂級(jí)節(jié)點(diǎn)可以不是數(shù)組或字典做盅。
     此外,NSJSONSerialization還提供了JSON編碼的方法: dataWithJSONObject;options:error:和writeJSONObject; toStream; options:error:,關(guān)于JSON的編碼方法的使用與解碼非常類似
     */
    id jsonObj = [NSJSONSerialization JSONObjectWithData:jsonData
                                                 options:NSJSONReadingMutableContainers error:&error];

    if (!jsonObj || error) {
        NSLog(@"JSON解碼失敗");
    }else{
       self.listData = [jsonObj objectForKey:@"Record"];
       //然后處理數(shù)據(jù)和刷新界面
    }
}

JSON是輕量級(jí)的數(shù)據(jù)交換格式,在應(yīng)用開發(fā)時(shí)候優(yōu)先考慮使用JSON而不是XML窘哈。XML的最優(yōu)解析框架是TBXML,JSON的最優(yōu)解碼框架是NSJSONSerialization吹榴。

  • 總結(jié)

XML與JSON兩種數(shù)據(jù)結(jié)構(gòu)的優(yōu)缺點(diǎn)

  1. XML

優(yōu)點(diǎn):

  • 格式統(tǒng)一, 符合標(biāo)準(zhǔn)
  • 容易與其他系統(tǒng)進(jìn)行遠(yuǎn)程交互, 數(shù)據(jù)共享比較方便

缺點(diǎn):

  • XML文件格式文件龐大, 格式復(fù)雜, 傳輸占用帶寬

  • 服務(wù)器端和客戶端都需要花費(fèi)大量代碼來解析XML, 不論服務(wù)器端和客戶端代碼變的異常復(fù)雜和不容易維護(hù)

  • 客戶端不同,瀏覽器之間解析XML的方式不一致, 需要重復(fù)編寫很多代碼

  • 服務(wù)器端 和 客戶端 解析XML花費(fèi)資源和時(shí)間

  1. JSON

優(yōu)點(diǎn):

  • 數(shù)據(jù)格式比較簡單, 易于讀寫, 格式都是壓縮的, 占用帶寬小

  • 易于解析這種語言

  • 支持多種語言, 包括ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby等語言服務(wù)器端語言, 便于服務(wù)器端的解析

  • 因?yàn)镴SON格式能夠直接為服務(wù)器端代碼使用, 大大簡化了服務(wù)器端和客戶端的代碼開發(fā)量, 但是完成的任務(wù)不變, 且易于維護(hù)

缺點(diǎn):

  • 沒有XML格式這么推廣的深入人心和使用廣泛, 沒有XML那么通用性
  • JSON格式目前在Web Service中推廣還屬于初級(jí)階段

XML和JSON的優(yōu)缺點(diǎn)對比

  1. 可讀性方面
    JSON和XML的數(shù)據(jù)可讀性基本相同滚婉,JSON和XML的可讀性可謂不相上下图筹,一邊是建議的語法,一邊是規(guī)范的標(biāo)簽形式满哪,XML可讀性較好些婿斥。
  2. 可擴(kuò)展性方面
    XML天生有很好的擴(kuò)展性,JSON當(dāng)然也有哨鸭,沒有什么是XML能擴(kuò)展民宿,JSON不能的。都具有很好的擴(kuò)展性像鸡。
  3. 編碼難度方面
    XML有豐富的編碼工具活鹰,比如Dom4j、JDom等只估,JSON也有json.org提供的工具志群,但是JSON的編碼明顯比XML容易許多,即使不借助工具也能寫出JSON的代碼蛔钙,可是要寫好XML就不太容易了锌云。相對而言:JSON的編碼比較容易。
  4. 解碼難度方面
    json解碼難度基本為零吁脱,xml需要考慮子節(jié)點(diǎn)和父節(jié)點(diǎn)桑涎。
  5. 傳輸速度方面
    JSON的速度要遠(yuǎn)遠(yuǎn)快于XML
  6. 流行度方面
    XML已經(jīng)被業(yè)界廣泛的使用,而JSON才剛剛開始兼贡,但是在Ajax這個(gè)特定的領(lǐng)域攻冷,未來的發(fā)展一定是XML讓位于JSON。到時(shí)Ajax應(yīng)該變成Ajaj(Asynchronous Javascript and JSON)了遍希。
  7. 解析手段方面
    JSON和XML同樣擁有豐富的解析手段等曼。
  8. 數(shù)據(jù)體積方面
    JSON相對于XML來講,數(shù)據(jù)的體積小凿蒜,傳遞的速度更快些禁谦。
  9. 數(shù)據(jù)交互方面
    JSON與JavaScript的交互更加方便,更容易解析處理废封,更好的數(shù)據(jù)交互枷畏。
  10. 數(shù)據(jù)描述方面
    JSON對數(shù)據(jù)的描述性比XML較差
  • XML與JSON數(shù)據(jù)格式比較

關(guān)于輕量級(jí)和重量級(jí)

輕量級(jí)和重量級(jí)是相對來說的虱饿,那么XML相對于JSON的重量級(jí)體現(xiàn)在哪呢?應(yīng)該體現(xiàn)在解析上拥诡,XML目前設(shè)計(jì)了兩種解析方式:DOM和 SAX。

  1. DOM
    DOM是把一個(gè)數(shù)據(jù)交換格式XML看成一個(gè)DOM對象氮发,需要把XML文件整個(gè)讀入內(nèi)存渴肉,這一點(diǎn)上JSON和XML的原理是一樣的,但是XML要考慮父節(jié)點(diǎn)和子節(jié)點(diǎn)爽冕,這一點(diǎn)上JSON的解析難度要小很多仇祭,因?yàn)镴SON構(gòu)建于兩種結(jié)構(gòu):key/value,鍵值對的集合;值的有序集合颈畸,可理解為數(shù)組乌奇;
  2. SAX
    SAX不需要整個(gè)讀入文檔就可以對解析出的內(nèi)容進(jìn)行處理没讲,是一種逐步解析的方法。程序也可以隨時(shí)終止解析礁苗。這樣爬凑,一個(gè)大的文檔就可以逐步的、一點(diǎn)一點(diǎn)的展現(xiàn)出來试伙,所以SAX適合于大規(guī)模的解析嘁信。這一點(diǎn),JSON目前是做不到得疏叨。
    所以潘靖,JSON和XML的輕/重量級(jí)的區(qū)別在于:
    JSON只提供整體解析方案,而這種方法只在解析較少的數(shù)據(jù)時(shí)才能起到良好的效果蚤蔓;
    XML提供了對大規(guī)模數(shù)據(jù)的逐步解析方案卦溢,這種方案很適合于對大量數(shù)據(jù)的處理
關(guān)于數(shù)據(jù)格式編碼及解析難度
  1. 在編碼方面秀又。
    雖然XML和JSON都有各自的編碼工具既绕,但是JSON的編碼要比XML簡單,即使不借助工具涮坐,也可以寫出JSON代碼凄贩,但要寫出好的XML代碼就有點(diǎn)困難;與XML一樣,JSON也是基于文本的袱讹,且它們都使用Unicode編碼疲扎,且其與數(shù)據(jù)交換格式XML一樣具有可讀性。
    主觀上來看捷雕,JSON更為清晰且冗余更少些椒丧。JSON網(wǎng)站提供了對JSON語法的嚴(yán)格描述,只是描述較簡短救巷。從總體來看壶熏,XML比較適合于標(biāo)記文檔,而JSON卻更適于進(jìn)行數(shù)據(jù)交換處理浦译。

  2. 在解析方面棒假。
    在普通的web應(yīng)用領(lǐng)域,開發(fā)者經(jīng)常為XML的解析傷腦筋精盅,無論是服務(wù)器端生成或處理XML帽哑,還是客戶端用 JavaScript 解析XML,都常常導(dǎo)致復(fù)雜的代碼叹俏,極低的開發(fā)效率妻枕。
    實(shí)際上,對于大多數(shù)Web應(yīng)用來說,他們根本不需要復(fù)雜的XML來傳輸數(shù)據(jù)屡谐,XML宣稱的擴(kuò)展性在此就很少具有優(yōu)勢,許多Ajax應(yīng)用甚至直接返回HTML片段來構(gòu)建動(dòng)態(tài)Web頁面述么。和返回XML并解析它相比,返回HTML片段大大降低了系統(tǒng)的復(fù)雜性愕掏,但同時(shí)缺少了一定的靈活性度秘。同XML或 HTML片段相比,數(shù)據(jù)交換格式JSON 提供了更好的簡單性和靈活性亭珍。在Web Serivice應(yīng)用中,至少就目前來說XML仍有不可動(dòng)搖的地位枝哄。

  3. 實(shí)例比較
    XML和JSON都使用結(jié)構(gòu)化方法來標(biāo)記數(shù)據(jù)肄梨,下面來做一個(gè)簡單的比較。

<?xml version="1.0" encoding="utf-8" ?>
<country>
  <name>中國</name>
  <province>
    <name>黑龍江</name>
    <citys>
      <city>哈爾濱</city>
      <city>大慶</city>
    </citys>    
  </province>
  <province>
    <name>廣東</name>
    <citys>
      <city>廣州</city>
      <city>深圳</city>
      <city>珠海</city>
    </citys>   
  </province>
  <province>
    <name>臺(tái)灣</name>
    <citys>
       <city>臺(tái)北</city>
       <city>高雄</city>
    </citys> 
  </province>
  <province>
    <name>新疆</name>
    <citys>
      <city>烏魯木齊</city>
    </citys>
  </province>
</country>

用JSON表示中國部分省市數(shù)據(jù)如下

 {
       name: "中國",
       provinces: [
             { name: "黑龍江", citys: { city: ["哈爾濱", "大慶"]} },
             { name: "廣東", citys: { city: ["廣州", "深圳", "珠海"]} },
             { name: "臺(tái)灣", citys: { city: ["臺(tái)北", "高雄"]} },
             { name: "新疆", citys: { city: ["烏魯木齊"]} }
            ]
 }

編碼的可讀性來說挠锥,XML有明顯的優(yōu)勢众羡,畢竟人類的語言更貼近這樣的說明結(jié)構(gòu)。JSON讀起來更像一個(gè)數(shù)據(jù)塊蓖租,讀起來就比較費(fèi)解了粱侣。不過,我們讀起來費(fèi)解的語言蓖宦,恰恰是適合機(jī)器閱讀齐婴,所以通過JSON的索引country.provinces[0].name就能夠讀取“黑龍江”這個(gè)值。
編碼的手寫難度來說稠茂,XML還是舒服一些柠偶,好讀當(dāng)然就好寫。不過寫出來的字符JSON就明顯少很多睬关。去掉空白制表以及換行的話诱担,JSON就是密密麻麻的有用數(shù)據(jù),而XML卻包含很多重復(fù)的標(biāo)記字符电爹。

參考文獻(xiàn):
JSON與XML的區(qū)別比較
IOS網(wǎng)絡(luò)編程與云端應(yīng)用最佳實(shí)踐.pdf

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蔫仙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子丐箩,更是在濱河造成了極大的恐慌摇邦,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屎勘,死亡現(xiàn)場離奇詭異涎嚼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)挑秉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門法梯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事立哑∫共眩” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵铛绰,是天一觀的道長诈茧。 經(jīng)常有香客問我,道長捂掰,這世上最難降的妖魔是什么敢会? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮这嚣,結(jié)果婚禮上鸥昏,老公的妹妹穿的比我還像新娘。我一直安慰自己姐帚,他們只是感情好吏垮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著罐旗,像睡著了一般膳汪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上九秀,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天遗嗽,我揣著相機(jī)與錄音,去河邊找鬼鼓蜒。 笑死媳谁,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的友酱。 我是一名探鬼主播晴音,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼缔杉!你這毒婦竟也來了锤躁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤或详,失蹤者是張志新(化名)和其女友劉穎系羞,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體霸琴,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡椒振,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了梧乘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澎迎。...
    茶點(diǎn)故事閱讀 39,703評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡庐杨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出夹供,到底是詐尸還是另有隱情灵份,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布哮洽,位于F島的核電站填渠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鸟辅。R本人自食惡果不足惜氛什,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望匪凉。 院中可真熱鬧枪眉,春花似錦、人聲如沸洒缀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽树绩。三九已至,卻和暖如春隐轩,著一層夾襖步出監(jiān)牢的瞬間饺饭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工职车, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瘫俊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓悴灵,卻偏偏與公主長得像扛芽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子积瞒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評論 2 353

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