iOS Apprentice中文版-從0開(kāi)始學(xué)iOS開(kāi)發(fā)-第四十三課

存儲(chǔ)位置信息

你已經(jīng)成功初始化Core Data泵额,并將NSManagedObjectContext傳遞給Tag Location界面移怯。 現(xiàn)在鄙早,當(dāng)用戶按下“Done”按鈕時(shí)撬腾,將新的Location對(duì)象放入數(shù)據(jù)存儲(chǔ)區(qū)。

打開(kāi)LocationDetailsViewController.swift装黑,添加一個(gè)新的實(shí)例變量:

var date = Date()

你添加這個(gè)變量是因?yàn)槟阈枰獙?dāng)前日期存儲(chǔ)到新的Location對(duì)象中副瀑,因此你需要一個(gè)Date對(duì)象。

在viewDidLoad()中曹体,將設(shè)置dateLabel的文本那一行語(yǔ)句修改為:

dateLabel.text = format(date: date)

這時(shí)新的這個(gè)變量就被用起來(lái)了俗扇。

將done方法修改為下面這個(gè)樣子:

@IBAction func done() {
        let hudView = HudView.hud(inView: navigationController!.view,
                                  animated: true)
        hudView.text = "Tagged"
        // 1
        let location = Location(context: managedObjectContext)
        // 2
        location.locationDescription = descriptionTextView.text
        location.category = categoryName
        location.latitude = coordinate.latitude
        location.longitude = coordinate.longitude
        location.date = date
        location.placemark = placemark
        // 3
        do {
            try managedObjectContext.save()
            afterDelay(0.6) {
                self.dismiss(animated: true, completion: nil)
            }
        } catch {
            fatalError("Error: \(error)")
        }
      }

它的工作原理是這樣的硝烂。

1箕别、首先,你創(chuàng)建了一個(gè)Location的實(shí)例滞谢。因?yàn)檫@是一個(gè)被管理的對(duì)象串稀,你必須使用它的init(context :)方法。 你不能只寫(xiě)Location()狮杨,這樣的話managedObjectContext將不知道新的對(duì)象是啥母截。

2、一旦創(chuàng)建了Location對(duì)象的實(shí)例橄教,你就可以像使用其他對(duì)象一樣使用它清寇。 在這里,你將其屬性設(shè)置為用戶在屏幕上輸入的內(nèi)容护蝶。

3华烟、現(xiàn)在,你已經(jīng)有了一個(gè)新的Location對(duì)象持灰,其屬性全部被填充盔夜,但如果你在此時(shí)查看數(shù)據(jù)存儲(chǔ)區(qū),那么你仍然不會(huì)在其中看到任何對(duì)象堤魁。 直到你使用save()保存后上下文才會(huì)發(fā)生喂链。

保存功能會(huì)將添加到上下文的任何對(duì)象或其內(nèi)容已更改的任何托管對(duì)象永久寫(xiě)入數(shù)據(jù)存儲(chǔ)區(qū)。 這就是為什么他們把上下文稱為“便箋簿(scratchpad)”妥泉。 它的變化會(huì)一直持續(xù)下去椭微,直到你保存它們。

save()方法可能由于各種原因而失敗盲链,因此你需要捕獲潛在的錯(cuò)誤蝇率。 這是使用Swift的do-try-catch功能完成的检诗。

do-try-catch

有時(shí)來(lái)自iOS SDK的操作可能會(huì)失敗并返回某種類型的錯(cuò)誤。 你已經(jīng)見(jiàn)過(guò)用于描述這種錯(cuò)誤的對(duì)象(NSError)瓢剿。 但是使用Error可能很麻煩逢慌,因?yàn)樗鼘?shí)際上是從Objective-C中借用的東西。

Swift有一個(gè)更好的方法來(lái)處理錯(cuò)誤间狂。 任何可能失敗的方法必須在其前面有try關(guān)鍵字攻泼。 用try關(guān)鍵字的方法調(diào)用必須在do-catch塊內(nèi)。

保存托管對(duì)象上下文是一個(gè)可能會(huì)失敗的操作鉴象。 這就是為什么你這樣寫(xiě)代碼:

do {
  try managedObjectContext.save()
  // code that runs when the “try” succeeds . . .
} catch {
  // code that runs when the “try” fails . . .
}

如果出現(xiàn)錯(cuò)誤忙菠,并且方法失敗 - 或者像我們所說(shuō)的那樣“拋出錯(cuò)誤”,應(yīng)用程序?qū)⑻^(guò)do部分的中所有代碼纺弊,并立即跳轉(zhuǎn)到catch部分來(lái)處理錯(cuò)誤牛欢。

如果你用使用過(guò)支持異常處理的語(yǔ)言,這可能看起來(lái)很熟悉淆游。 任何可能引發(fā)錯(cuò)誤的方法調(diào)用都必須寫(xiě)為try methodName()傍睹。 這會(huì)很容易找出哪些方法調(diào)用引發(fā)了錯(cuò)誤。

在本教程的后面犹菱,你將看到更多的do-try-catch示例拾稳。 這是Swift中非常重要的課題,因?yàn)闆](méi)有人喜歡錯(cuò)誤腊脱。 他們必須被抓追玫谩!

運(yùn)行app陕凹,獲得一個(gè)位置信息悍抑,并且添加一段描述后點(diǎn)擊Done按鈕。

如果一切正常杜耙,Core Data會(huì)在調(diào)試區(qū)域打印下列信息:

CoreData: sql: BEGIN EXCLUSIVE ...
CoreData: sql: INSERT INTO ZLOCATION(Z_PK, Z_ENT, Z_OPT, ZCATEGORY,
ZDATE, ZLATITUDE, ZLOCATIONDESCRIPTION, ZLONGITUDE, ZPLACEMARK) VALUES(?,
?, ?, ?, ?, ?, ?, ?, ?)
CoreData: sql: COMMIT
...
CoreData: annotation: sql execution time: 0.0001s

這些是Core Data執(zhí)行存儲(chǔ)新的Location對(duì)象到數(shù)據(jù)庫(kù)中所執(zhí)行的SQL語(yǔ)句搜骡。

??:Xcode8中不會(huì)打印這些信息。

打開(kāi)Liya軟件泥技,刷新ZLOCATION表(點(diǎn)擊Go按鈕)浆兰,這時(shí)你可以看到表中出現(xiàn)了新的一行。

如果你在表中沒(méi)有看到任何行珊豹,請(qǐng)先按Xcode中的“Stop”按鈕退出應(yīng)用程序簸呈。 也可以嘗試關(guān)閉Liya窗口并打開(kāi)到數(shù)據(jù)庫(kù)的新連接。

如你所見(jiàn)店茶,此表中的列包含Location對(duì)象的屬性值蜕便。 唯一不可讀的列是ZPLACEMARK。 其內(nèi)容已被編碼為二進(jìn)制“blob”數(shù)據(jù)贩幻。 這是因?yàn)樗且粋€(gè)轉(zhuǎn)換后的屬性轿腺,NSCoding協(xié)議已經(jīng)把它的字段轉(zhuǎn)換成二進(jìn)制數(shù)據(jù)塊两嘴。

如果你沒(méi)有Liya或者你是一個(gè)命令行的癮君子,那么還有另外一種方法來(lái)檢查數(shù)據(jù)庫(kù)的內(nèi)容族壳。 你可以使用終端應(yīng)用程序和sqlite3工具憔辫,但是不推薦這樣做:

處理Core Data錯(cuò)誤

將上下文的內(nèi)容保存到數(shù)據(jù)存儲(chǔ)區(qū),你使用了如下代碼:

do {
try managedObjectContext.save() ...
} catch {
  fatalError("Error: \(error)")
}

如果保存有什么問(wèn)題怎么辦仿荆? 在這種情況下贰您,try跳轉(zhuǎn)到catch部分,并調(diào)用fatalError()函數(shù)拢操。 這會(huì)立即中斷掉app锦亦,并將用戶返回到iPhone的界面。 這對(duì)用戶來(lái)說(shuō)是非常粗暴的令境,因此不推薦這樣做杠园。

好消息是,如果你試圖保存無(wú)效的內(nèi)容舔庶,Core Data只會(huì)給出一個(gè)錯(cuò)誤抛蚁。 換句話說(shuō),此時(shí)你的app存在BUG栖茉。

當(dāng)然篮绿,在開(kāi)發(fā)過(guò)程中你可以解決掉所有的bug,所以用戶將永遠(yuǎn)不會(huì)遇到任何bug吕漂,對(duì)嗎? 可悲的是尘应,你永遠(yuǎn)不會(huì)趕上你所有的bug惶凝。 有些bug總是會(huì)設(shè)法溜過(guò)去。

壞消息是當(dāng)Core Data崩潰時(shí)犬钢,你無(wú)法進(jìn)行過(guò)多的干預(yù)苍鲜。 有些地方出現(xiàn)了可怕的bug,比如現(xiàn)在你被無(wú)效的數(shù)據(jù)困住了玷犹。 如果app被允許繼續(xù)運(yùn)行混滔,事情可能只會(huì)變得更糟,因?yàn)槟悴恢繿pp處于什么狀態(tài)歹颓。最后的事就是用戶的數(shù)據(jù)會(huì)被破壞掉坯屿。

不要用fatalError()讓app崩潰,而是首先告訴用戶這個(gè)問(wèn)題巍扛,至少他們知道發(fā)生了什么领跛。 崩潰仍然是不可避免的,但現(xiàn)在你的用戶會(huì)知道為什么應(yīng)用程序突然停止工作撤奸。

在本節(jié)中吠昭,你將添加一個(gè)彈出警報(bào)來(lái)處理這種情況喊括。 當(dāng)然,這些bug只會(huì)在開(kāi)發(fā)過(guò)程中發(fā)生矢棚,但是如果他們確實(shí)發(fā)生在實(shí)際的用戶身上郑什,那么你至少應(yīng)該試著用一點(diǎn)點(diǎn)比較和諧的手段來(lái)處理它。

我們通過(guò)一些方法來(lái)制造點(diǎn)麻煩蒲肋,看看會(huì)發(fā)生什么蹦误。

打開(kāi)數(shù)據(jù)模型文件(DataModel.xcdatamodeld ),然后選擇placemark屬性肉津。然后取消選擇Optional選項(xiàng)强胰。

image.png

這就是說(shuō)location.placemark不再是一個(gè)可選型了。這是Core Data強(qiáng)制執(zhí)行的一個(gè)約束條件妹沙。 當(dāng)你嘗試保存為nil的location時(shí)偶洋,Core Data就會(huì)崩潰掉。 所以我們可以利用這一點(diǎn)來(lái)進(jìn)行測(cè)試距糖。

運(yùn)行app玄窝。看看效果悍引。恩脂。。

你剛剛通過(guò)更改placemark屬性來(lái)變更 了數(shù)據(jù)模型趣斤。 在啟動(dòng)應(yīng)用程序時(shí)俩块,NSPersistentContainer會(huì)注意到這一點(diǎn),并嘗試將SQLite數(shù)據(jù)庫(kù)執(zhí)行所謂的“遷移”到更新后的數(shù)據(jù)模型上浓领。

遷移可能成功玉凯,也可能不成功,這依賴于數(shù)據(jù)存儲(chǔ)中當(dāng)前的內(nèi)容联贩。 如果之前的placemark為nil漫仆,則遷移到新數(shù)據(jù)模型將失敗。 畢竟泪幌,新的數(shù)據(jù)模型不允許為nil的placemark盲厌。

此時(shí),你應(yīng)該可以在調(diào)試區(qū)域看到如下信息:

reason=Cannot migrate store in-place: Validation error missing attribute
values on mandatory destination attribute, . . . {entity=Location,
attribute=placemark, . . .}

DataModel.sqlite文件對(duì)于已更改的數(shù)據(jù)模型已經(jīng)無(wú)法適應(yīng)祸泪,并且Core Data不能自動(dòng)解決這個(gè)問(wèn)題吗浩。

有兩種方法可以解決這個(gè)問(wèn)題:1)簡(jiǎn)單地刪掉Library目錄下的DataModel.sqlite文件; 2)從模擬器中刪除整個(gè)app。

刪除DataModel.sqlite文件浴滴,以及-shm和-wal文件拓萌,然后再次運(yùn)行app。

我們的重點(diǎn)并不是觀看app如何崩潰升略,而是一定要謹(jǐn)記數(shù)據(jù)模型變更后微王,你需要拋棄之前的數(shù)據(jù)庫(kù)文件屡限,否則Core Data無(wú)法正常初始化。

??:如果NSPersistentContainer遷移失敗炕倘,并不會(huì)全部丟失钧大。 Core Data允許你在使用新數(shù)據(jù)模型時(shí)向你的app發(fā)布更新并自己執(zhí)行遷移。 比起讓app崩潰罩旋,這種機(jī)制允許你將用戶現(xiàn)有數(shù)據(jù)存儲(chǔ)的內(nèi)容轉(zhuǎn)換為新模型啊央。 但是,在開(kāi)發(fā)時(shí)還是直接刪除掉原有的文件比較簡(jiǎn)單涨醋。

看這樣一個(gè)場(chǎng)景瓜饥,點(diǎn)擊Get My Location按鈕,然后點(diǎn)擊Tag Location浴骂。 如果你足夠快的話乓土,地址解析就會(huì)失敗,Tag Location界面將會(huì)顯示:“No Address Found”溯警。 僅當(dāng)placemark為nil時(shí)才會(huì)顯示這條信息趣苏。

可以通過(guò)注釋掉CurrentLocationViewController.swift中的locationManager(didUpdateLocations)中的self.placemark = p.last!這一行來(lái)偽造地址解析過(guò)快的現(xiàn)象 梯轻。 這會(huì)使得看起來(lái)沒(méi)有地址被搜索到食磕,并且placemark的值為 nil。

點(diǎn)擊Done按鈕來(lái)保存新的location對(duì)象喳挑。

app將會(huì)調(diào)用fatalError()并且崩潰掉彬伦。

image.png

你會(huì)在調(diào)試區(qū)域看到如下信息:

The operation couldn’t be completed . . . NSValidationErrorKey=placemark

意思是placemark屬性沒(méi)有值。因?yàn)槟惆阉O(shè)置為非可選型了蟀悦,Core Data無(wú)法接受placemark的值為nil媚朦。

當(dāng)然,剛剛看到的只是在Xcode中運(yùn)行應(yīng)用程序時(shí)才會(huì)發(fā)生日戈。 當(dāng)它崩潰時(shí),調(diào)試器接管app并指向錯(cuò)誤行孙乖。 但這不是用戶所看到的浙炼。

點(diǎn)擊Stop按鈕關(guān)閉app。現(xiàn)在點(diǎn)擊模擬器中的app圖標(biāo)唯袄,在Xcode之外啟動(dòng)app弯屈。 重復(fù)相同的操作,使app崩潰恋拷。 app將停止運(yùn)作资厉,并從屏幕上消失。你作為用戶什么都看不到蔬顾。

想象一下宴偿,剛剛為你的應(yīng)用付了99美分(或更多)的用戶就會(huì)遇到這種情況湘捎。 他們會(huì)非常困惑,“剛剛發(fā)生了什么窄刘?窥妇!”此時(shí)你并沒(méi)有什么給用戶解釋的機(jī)會(huì),只能接受退款給他們娩践。

發(fā)生這種情況時(shí)最好顯示一個(gè)提示活翩。 在用戶確認(rèn)之后,app依然會(huì)崩潰翻伺,但至少用戶知道原因材泄。 (提示消息應(yīng)該讓用戶聯(lián)系你,由你來(lái)解釋一下怎么回事吨岭,這樣你至少有機(jī)會(huì)在下一個(gè)版本中修復(fù)這個(gè)問(wèn)題拉宗。)

打開(kāi)Functions.swift,并且添加以下代碼:

let MyManagedObjectContextSaveDidFailNotification = Notification.Name(
    rawValue: "MyManagedObjectContextSaveDidFailNotification")
func fatalCoreDataError(_ error: Error) {
    print("*** Fatal error: \(error)")
    NotificationCenter.default.post(
        name: MyManagedObjectContextSaveDidFailNotification, object: nil)
}

這里定義了一個(gè)新的全局函數(shù)來(lái)處理致命的Core Data錯(cuò)誤未妹。

打開(kāi)LocationDetailsViewController.swift在done()方法中簿废,替換掉處理錯(cuò)誤的代碼。

do {
try managedObjectContext.save() ...
} catch {
  fatalCoreDataError(error)
}

這里使用 fatalCoreDataError(error)替換掉了fatalError()络它。那么這個(gè)新的方法到底做了些什么事呢族檬?

它首先使用print()將錯(cuò)誤消息輸出到調(diào)試區(qū)域,因?yàn)橛涗涍@樣的錯(cuò)誤總是有用的化戳。 在這之后单料,執(zhí)行以下操作:

NotificationCenter.default.post(name: MyManagedObjectContextSaveDidFailNotification, object: nil)

我一直在使用術(shù)語(yǔ)“通知(notification)”來(lái)表示任何通用事件或消息正在交付,但iOS SDK也有一個(gè)名為NotificationCenter的對(duì)象(不要和你的手機(jī)上的通知中心混淆)点楼。

上面的代碼使用NotificationCenter發(fā)布通知扫尖。 你的app中的任何對(duì)象都可以訂閱此類通知,如果發(fā)生這些通知掠廓,NotificationCenter將在這些偵聽(tīng)器對(duì)象上調(diào)用某個(gè)方法换怖。

使用這個(gè)官方的通知系統(tǒng)是使你的對(duì)象可以相互溝通的另一種方式。 它的方便之處在于蟀瞧,發(fā)送通知的對(duì)象和接收通知的對(duì)象不需要彼此知道任何事情沉颂。 發(fā)件人只是發(fā)送通知,但并不在乎發(fā)生了什么事情悦污。 如果有人在聽(tīng)铸屉,太好了。 如果沒(méi)有切端,那么也無(wú)所謂彻坛。

UIKit定義了許多可以訂閱的標(biāo)準(zhǔn)通知。 例如,有一個(gè)通知讓你知道昌屉,當(dāng)用戶點(diǎn)擊Home按鈕時(shí)钙蒙,app即將被暫停。

你也可以定義自己的通知怠益,這就是你剛才所做的仪搔。 新的通知被稱為MyManagedObjectContextSaveDidFailNotification。

思路是蜻牢,app中有一個(gè)地方監(jiān)聽(tīng)這個(gè)通知烤咧,彈出一個(gè)警報(bào)視圖,并終止app抢呆。 使用NotificationCenter的好處是你的Core Data代碼部分不需要關(guān)心這些煮嫌。

無(wú)論何時(shí)保存發(fā)生錯(cuò)誤,無(wú)論app中的哪一點(diǎn)抱虐,fatalCoreDataError()函數(shù)都會(huì)發(fā)出此通知昌阿,因?yàn)樗嘈牌渌麑?duì)象正在偵聽(tīng)通知并處理錯(cuò)誤。

那么誰(shuí)來(lái)處理這個(gè)錯(cuò)誤恳邀? app delegate是一個(gè)很好的地方懦冰。 這是app中頂級(jí)的一個(gè)對(duì)象,你總是保證這個(gè)對(duì)象是存在的谣沸。

在AppDelegate.swift中添加以下方法:

func listenForFatalCoreDataNotifications() {
        // 1
        NotificationCenter.default.addObserver(
            forName: MyManagedObjectContextSaveDidFailNotification,
            object: nil, queue: OperationQueue.main, using: { notification in
                // 2
                let alert = UIAlertController(
                    title: "Internal Error",
                    message:
                    "There was a fatal error in the app and it cannot continue.\n\n"
                        + "Press OK to terminate the app. Sorry for the inconvenience.",
                    preferredStyle: .alert)
                // 3
                let action = UIAlertAction(title: "OK", style: .default) { _ in
                    let exception = NSException(
                        name: NSExceptionName.internalInconsistencyException,
                        reason: "Fatal Core Data error", userInfo: nil)
                    exception.raise()
                }
                alert.addAction(action)
                // 4
                self.viewControllerForShowingAlert().present(alert, animated: true,completion:nil)
                
        })
    }
    // 5
    func viewControllerForShowingAlert() -> UIViewController {
        let rootViewController = self.window!.rootViewController!
        if let presentedViewController =
            rootViewController.presentedViewController {
            return presentedViewController
        } else {
            return rootViewController
        }
    }

我們一步步的來(lái)看一下:

1刷钢、告訴通知中心,每當(dāng)發(fā)布MyManagedObjectContextSaveDidFailNotification時(shí)乳附,都要通知你内地。

2、創(chuàng)建一個(gè)UIAlertController用于展示錯(cuò)誤消息赋除。

3阱缓、為警報(bào)彈窗的OK按鈕添加一個(gè)操作。處理按鈕按下的代碼
還是閉包(閉包這些東西無(wú)處不在>倥)荆针。 閉包創(chuàng)建一個(gè)NSException對(duì)象來(lái)終止應(yīng)用程序,而不是使用fatalError()颁糟。這樣的好處是祭犯,它提供了更多的信息到日志。

4滚停、最后,展現(xiàn)這個(gè)警報(bào)彈窗粥惧。

5键畴、為了通過(guò)present(animated,completion)方法來(lái)展示這個(gè)警報(bào)彈窗,你需要一個(gè)當(dāng)前可見(jiàn)的視圖控制器,所以這個(gè)方法就自己找了一個(gè)起惕。 不幸的是涡贱,你不能簡(jiǎn)單地使用窗口的rootViewController(在這個(gè)app中rootViewController就是tab bar controller),因?yàn)楫?dāng)Location Dteails界面打開(kāi)時(shí)惹想,它是處于隱藏狀態(tài)的问词。

剩下的就是調(diào)用一個(gè)新的listenForFatalCoreDataNotifications()方法,以便通知處理程序向NotificationCenter注冊(cè)嘀粱。

將以下內(nèi)容添加到application(didFinishLaunchingWithOptions)中激挪,就在return true語(yǔ)句之前:

listenForFatalCoreDataNotifications()

再次運(yùn)行app,并嘗試在獲得街道地址之前標(biāo)記位置锋叨。 現(xiàn)在垄分,app還是會(huì)崩潰,但是至少它告訴用戶發(fā)生了什么事情:

我應(yīng)該再?gòu)?qiáng)調(diào)一次娃磺,你必須對(duì)你的app進(jìn)行完善的測(cè)試薄湿,以確保你沒(méi)有給Core Data任何未驗(yàn)證過(guò)的對(duì)象。 你需要不惜一切代價(jià)避免這些存儲(chǔ)錯(cuò)誤偷卧!

理想情況下豺瘤,用戶不應(yīng)該看到該警報(bào)彈窗,但它必須存在听诸,因?yàn)闆](méi)有任何保證你的app不會(huì)有錯(cuò)誤坐求。

??:你可以合理地使用managedObjectContext.save()讓Core Data驗(yàn)證用戶輸入。 并不是說(shuō)每當(dāng)存儲(chǔ)失敗蛇更,你都要使app崩潰掉瞻赶,只有發(fā)生哪些不可預(yù)期的錯(cuò)誤時(shí)才會(huì)這樣做。
除了可選型之外派任,還有更多的驗(yàn)證設(shè)置可以放在實(shí)體的屬性上砸逊。如果你允許你的用戶輸入這些實(shí)體屬性,那么最好用save()去驗(yàn)證一下掌逛。如果save()方法拋出了一個(gè)錯(cuò)誤师逸,那么用戶的任何輸入都是無(wú)效的,你必須妥善處理這種情況豆混。

打開(kāi)數(shù)據(jù)模型文件篓像,重新將placemark屬性設(shè)置為可選型。

運(yùn)行app皿伺,看看是否一切正常员辩。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市鸵鸥,隨后出現(xiàn)的幾起案子奠滑,更是在濱河造成了極大的恐慌丹皱,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宋税,死亡現(xiàn)場(chǎng)離奇詭異摊崭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)杰赛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門呢簸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人乏屯,你說(shuō)我怎么就攤上這事根时。” “怎么了瓶珊?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵啸箫,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我伞芹,道長(zhǎng)忘苛,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任唱较,我火速辦了婚禮扎唾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘南缓。我一直安慰自己胸遇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布汉形。 她就那樣靜靜地躺著纸镊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪概疆。 梳的紋絲不亂的頭發(fā)上逗威,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音岔冀,去河邊找鬼凯旭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛使套,可吹牛的內(nèi)容都是我干的罐呼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼侦高,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼嫉柴!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起奉呛,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤差凹,失蹤者是張志新(化名)和其女友劉穎期奔,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體危尿,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年馁痴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谊娇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡罗晕,死狀恐怖济欢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情小渊,我是刑警寧澤法褥,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站酬屉,受9級(jí)特大地震影響半等,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜呐萨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一杀饵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谬擦,春花似錦切距、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至北秽,卻和暖如春葡幸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背羡儿。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工礼患, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人掠归。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓缅叠,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親虏冻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子肤粱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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