大寶劍之精挑細選——CoreData(四)

大寶劍的挑選是莊嚴而神圣的,必須一絲不茍的完成,防止出現自己約的炮含淚也得打完的慘劇。
(回到正題)當我們讀取數據時,并不是每份數據都需要的,比如說有時候我們只想要女生的QQ~~~~~男生的QQ這時候給我我還得一個一個來挑選,又偏了~~

  • 參考書籍:CORE DATA by Tutorials。
  • 默認有swift基礎。
  • 默認已閱讀上一篇內容。

這一篇的內容:

  • 按條件查詢返回數量
  • 按條件查詢
  • 排序
  • 異步查詢
  • 批量同步

我們知道讀取數據之前我們必須創建一個讀取請求,這個讀取請求就是NSFetchRequest,這里有四種方法來創建一個NSFetchRequest
<pre><code>
//1
let fetchRequest1 = NSFetchRequest()
let entity = NSEntityDescription.entityForName("Person",
inManagedObjectContext: managedObjectContext!) fetchRequest1.entity = entity!
//2
let fetchRequest2 = NSFetchRequest(entityName: "Person")
//3
let fetchRequest3 = managedObjectModel.fetchRequestTemplateForName("peopleFR")
//4
let fetchRequest4 = managedObjectModel.fetchRequestFromTemplateWithName("peopleFR",
substitutionVariables: ["NAME" : "Ray"])
</code></pre>

Have a look:

  • //1 //2這兩種就不多說了,前面的篇章都遇到過,就是通過不同方法初始化,然后指定了Entity。
  • //3 這種方法用data model中的fetch request來初始化,關于data model中的這個屬性,在后面會提到。
  • //4 這種方法同樣使用了data model中的fetch request,同時設定了一個斷言,來限定最后的輸出結果。

一如既往的,我們每一個篇章都會有一個Demo,今天的這個Demo較為復雜,由書籍CORE DATA by Tutorials提供,來看一下這個Demo:

在這個界面會顯示所有的奶茶店,點擊Filter按鈕以后會跳轉到刪選條件的界面。


2.png

在個界面會顯示刪選條件,刪選條件包括價格區間,$表示十美元以內,$$表示出售100美元的奶茶店,$$$表示出售1000美元奶茶的店。刪選條件還包括距離,是否有用戶評價,還有根據字母排序........
來看一下文件結構:


3.png

其中Stats.seift、Venue.swift、Location.swift、PriceInfo.swift、Category.swift都是Entity生成的類,其他的文件都不是特別復雜,就不多說。注意一下seed.json文件,這個文件提供了紐約地區真實的奶茶店情況~

開始完善我們的Demo,我們首先要做的就是將所有的奶茶店顯示在TableView中,而所有的奶茶店則是存儲在Venue這個Entity中,所以我們要創建一個Fetch Request讀取Venue中的所有數據,至于這些數據什么時候存進去的?打開我們的AppDelegate.swift,我們在進入程序的最開始已經將seed.json中的所有數據都存起來了,至于怎么存的,這不在今天的考慮當中。
打開Model.xcdatamodeld,長按Add Entity,不要放開鼠標,選擇Add Fetch Request,這樣我們在data model中添加了一個Fetch Request,

4.png

選擇我們新建的Fetch Request,將Fetch All選擇為Venue,這一步講Fetch Request與Entity聯系起來:
與Entity聯系起來

打開ViewConreoller.swift,先是添加頭文件

      import CoreData

添加存放讀取數據的數組,和讀取數據的請求:

  var fetchRequest: NSFetchRequest!
  var venues: [Venue]!

在viewDidLoad方法中添加一下代碼:
<pre><code>
//1
fetchRequest = coreDataStack.model.fetchRequestTemplateForName("FetchRequest")
//2
fetchAndReload()

</code></pre>

  • //1 這個就是我們前面提到的第三種創建Fetch Request的方法,這種方法從data model中創建的Fetch Request來進行初始化,而在模板中我們已經吧這個Fetch Request與Entity聯系起來了。
  • //2 這個方法我們在TableView中顯示數據,當然我們還沒有添加這個方法,接下來就是添加這個方法:

<pre><code>
func fetchAndReload(){
var error: NSError?
let results = coreDataStack.context.executeFetchRequest(fetchRequest,error: &error) as! [Venue]?
if let fetchedResults = results { venues = fetchedResults
} else {
println("Could not fetch (error), (error!.userInfo)")
}
tableView.reloadData()
}
</pre></code>

這個方法就不進行解釋了,前面的篇章中已經反復寫過很多次了。
我們已經把所有的奶茶店的數據都讀取到[Venue]數組中了,接下來就是在TableView中顯示這些數據,以下代碼:

<pre><code>
func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int {
return venues.count
}
func tableView(tableView: UITableView!, cellForRowAtIndexPath
indexPath: NSIndexPath!) -> UITableViewCell! {
var cell = tableView.dequeueReusableCellWithIdentifier("VenueCell") as! UITableViewCell
let venue = venues[indexPath.row]
cell.textLabel!.text = venue.name
cell.detailTextLabel!.text = venue.priceInfo.priceCategory
return cell
}
</code></pre>

代碼簡單就不進行解釋了,有問題的同學,可以留言提問,好的,來讓我們運行下程序吧。


大功告成,成功將所有的奶茶店顯示在了界面上

NSFetchReuqest是多功能的,他的返回值不僅僅可以是對象,他同樣可以查詢數據的數量,平均值、最大值、最小值······他有一個屬性叫做resultType通過設定這個屬性,你可以通過查詢返回不同的結果,這是所有的返回類型:

  • NSManagedObjectResultType:這是默認的選項,返回了所有的對象。
  • NSCountResultType:返回所有對象的數量。
  • NSDictionaryResultType:對查詢結果進行統計,包括求和,最大值,最小值等等等。好多好多,要不要列出來?算來還不列了,點進xcode的解釋里頭,全列出來了。
  • NSManagedObjectIDResultType: 返回所有對象的ID,這個方法現在已經被淘汰了,淘汰了就不多說了。

返回數量

來到我們的刪選界面,在這個界面的最上節,我們將返回不同價格的奶茶店的數量。
打開FilterViewController.swift,添加以下代碼:

   import CoreData
   var coreDataStack:CoreDataStack!

返回ViewController.swift,在prepareForSegue函數中添加以下代碼:

  filterVC.coreDataStack = coreDataStack

將暫存器傳過去~~而不用重新新建一個。

再回到FilterViewController.swift,我們首先創建一個懶惰屬性:
<pre><code>
lazy var cheapVenuePredicate: NSPredicate = {
var predicate = NSPredicate(format: "priceInfo.priceCategory == %@", "$")
return predicate
}()

</code></pre>

懶惰屬性的意思就是在使用到這個屬性的時候才會去創建這個變量,而不是在最開始創建。那么這個懶惰屬性的作用是什么呢,這個懶惰屬性可以限定我們的查詢結果,在這個懶惰屬性中,就是限定priceInfo.priceCategory是“$”,繼續在這個頁面中添加以下代碼:
<pre><code>
func populateCheapVenueCountLabel() {
// $ fetch request
//1
let fetchRequest = NSFetchRequest(entityName: "Venue")
//2
fetchRequest.resultType = NSFetchRequestResultType.CountResultType
fetchRequest.predicate = cheapVenuePredicate
//3
var error: NSError?
let result = coreDataStack.context.executeFetchRequest(fetchRequest,error: &error) as! [NSNumber]?
if let countArray = result {
let count = countArray[0].integerValue
firstPriceCategoryLabel.text = "(count) bubble tea places"
} else {
println("Could not fetch (error), (error!.userInfo)")
}
}
override func viewDidLoad() {
super.viewDidLoad()
populateCheapVenueCountLabel()
}
</code></pre>

  • //1 新建了一個** NSFetchRequest**
  • //2 指定了resultType為NSFetchRequestResultType.CountResultType,當這么指定以后,讀取的返回結果就是對象的數量。
    指定了刪選條件,就是我們之前設定的斷言。
  • //3 讀取結果,結果返回一個NSNumber的數組,這個數組只有一個值,所以我們獲取個數保存在result[0]中。
    將讀取到的結果顯示在界面上。

同樣的道理,我們用同樣的方法獲取了價格為“$$”的個數。代碼如下:
<pre><code>
lazy var moderateVenuePredicate: NSPredicate = {
var predicate = NSPredicate(format: "priceInfo.priceCategory == %@", "$$")
return predicate
}()
func populateModerateVenueCountLabel() {
// $$ fetch request
let fetchRequest = NSFetchRequest(entityName: "Venue")
fetchRequest.resultType = .CountResultType
fetchRequest.predicate = moderateVenuePredicate
var error: NSError?
let result = coreDataStack.context.executeFetchRequest(fetchRequest,error: &error) as! [NSNumber]?
if let countArray = result {
let count = countArray[0].integerValue
secondPriceCategoryLabel.text = "(count) bubble tea places"
} else {
println("Could not fetch (error), (error!.userInfo)")
}
}
</code></pre>

我們現在來運行一下程序來看一下結果,如下圖所示:


1.png

我們已經計算出了“$”和"$$"的價格的奶茶店的個數,事實上我們有一種更好的方式來計算對象的個數,如以下代碼所示:
<pre><code>
lazy var expensiveVenuePredicate: NSPredicate = {
var predicate = NSPredicate(format: "priceInfo.priceCategory == %@", "$$$")
return predicate
}()
func populateExpensiveVenueCountLabel() {
// $$$ fetch request
let fetchRequest = NSFetchRequest(entityName: "Venue")
fetchRequest.predicate = expensiveVenuePredicate
var error: NSError?
let count = coreDataStack.context.countForFetchRequest(fetchRequest,error: &error)
if count == NSNotFound {
println("Could not fetch (error), (error!.userInfo)")
}
thirdPriceCategoryLabel.text = "(count) bubble tea places"
}

</code></pre>

同樣我們設定了一個斷言,來限制了查詢結果,但是在這里我們沒有設定他的返回就結果,而是用到了這樣一個方法

 func countForFetchRequest(request: NSFetchRequest, error: NSErrorPointer) -> Int

這個方法同樣會返回查詢結果對象的數量。來看一下最終的運行結果吧:

1.png

wonderful!!~~~,一共27家“$”級別奶茶店,兩家"$$"級別奶茶店,一家"$$$"級別奶茶店。

呼呼~~~休息休息,我去喝杯奶茶再回來~


X只能喝一杯十元的奶茶了,很想知道那千元奶茶店,賣的是啥~~~

好的我們來完成第二個模塊。
對各種服務進行統計,就是我們前面提到的第三種返回類型,真的是很黃很暴力哈。添加以下代碼:
<pre><code>
func populateDealsCountLabel() {
//1
let fetchRequest = NSFetchRequest(entityName: "Venue")
fetchRequest.resultType = .DictionaryResultType
//2
let sumExpressionDesc = NSExpressionDescription()
sumExpressionDesc.name = "sumDeals"
//3
sumExpressionDesc.expression = NSExpression(forFunction: "sum:",arguments:[NSExpression(forKeyPath: "specialCount")])
sumExpressionDesc.expressionResultType = NSAttributeType.Integer32AttributeType
//4
fetchRequest.propertiesToFetch = [sumExpressionDesc]
//5
var error: NSError?
let result = coreDataStack.context.executeFetchRequest(fetchRequest,error: &error) as! [NSDictionary]?
if let resultArray = result {
let resultDict = resultArray[0]
let numDeals: AnyObject? = resultDict["sumDeals"]
numDealsLabel.text = "(numDeals!) total deals"
} else {
println("Could not fetch (error), (error!.userInfo)")
}
}
</code></pre>

  • //1 新建一個NSFetchRequest,將返回類型設定為 . DictionaryResultType。
  • 因為返回類型是一個字典形,所以在這里要設置key為sumDeals,也就是這里的name。
  • 這里統計的是specialCount的和,** forFunction**填的是“sum:”其實這里有好多可以填的,點進這個方法,你可以看到好多~好多~好多~~其實這里就是給設定一個統計的方式。
  • 設定** .propertiesToFetch**屬性。
  • 發出請求,返回一個字典型。key就是我們前面設定的sumDeals。

運行一下APP:

一共12次交易記錄

接下來的功能是這樣的:在Fiters界面選擇刪選條件以后,點擊右上方的Search按鈕,返回上一屆面,按條件顯示對象,那我們第一步要做的就是將選擇的條件返回上一界面,再上一界面的TableView中顯示符合條件的對象,我們用協議來傳遞參數,添加協議:
<pre><code>
protocol FilterViewControllerDelegate: class {
func filterViewController(filter: FilterViewController,didSelectPredicate predicate:NSPredicate?,sortDescriptor:NSSortDescriptor?)
}
</code></pre>

在Search方法中添加以下代碼
<pre><code>
@IBAction func saveButtonTapped(sender: UIBarButtonItem) {
delegate!.filterViewController(self, didSelectPredicate: selectedPredicate, sortDescriptor: selectedSortDescriptor)
dismissViewControllerAnimated(true, completion:nil)
}
</code></pre>

這段代碼很明顯就是在點擊Search按鈕,返回界面以前執行在viewConreoller中的方法** filterViewController**,并將參數傳過去。
添加刪選條件參數變量,前面提到了兩種刪選條件變量類型,NSSortDescriptor和NSPredicate:
<pre><code>
weak var delegate: FilterViewControllerDelegate?
var selectedSortDescriptor: NSSortDescriptor?
var selectedPredicate: NSPredicate?
</code></pre>

前面我們已經刪選過"$","$$","$$$"三個價位的奶茶店的數量,現在我們來顯示符合條件的奶茶店,和之前的區別在哪里,區別就是前面我們的查詢返回結果是NSFetchRequestResultType.CountResultType,而現在則是默認的,返回對象即可,而我們之前寫的刪選條件則是一樣的,在

   func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 

中添加選擇結果:
<pre><code>
//1
let cell = tableView.cellForRowAtIndexPath(indexPath)!
switch cell {
// Price section
case cheapVenueCell:
selectedPredicate = cheapVenuePredicate
case moderateVenueCell:
selectedPredicate = moderateVenuePredicate
case expensiveVenueCell:
selectedPredicate = expensiveVenuePredicate
default:
println("default case"
}
//2
cell.accessoryType = .Checkmark
</code></pre>

  • //1 根據選擇結果,確定判斷條件,這三個斷言在之前已經寫過了。
  • //2 這個只是給選擇的項目打個勾,而已~~~~

好的我們來到viewController.swift來實現一下代理方法,并添加代理:
添加代理:

 class ViewController: UIViewController,FilterViewControllerDelegate{

prepareForSegue方法中添加(關于協議,就不解釋了~~不懂的可以留言~):

 filterVC.delegate = self

好的,實現方法:
<pre><code>
func filterViewController(filter: FilterViewController, didSelectPredicate predicate:NSPredicate?, sortDescriptor:NSSortDescriptor?) {
//1
fetchRequest.predicate = nil
fetchRequest.sortDescriptors = nil
//2
if let fetchPredicate = predicate {
fetchRequest.predicate = fetchPredicate
}
if let sr = sortDescriptor {
fetchRequest.sortDescriptors = [sr]
}
//3
fetchAndReload()
}
</code></pre>

  • //1 先將兩個參數初始化為nil,因為我們傳過來的判斷條件參數只有一個是有值。
  • //2 用if let來判斷到底哪個參數是有值的。
  • //3 最后一步更新一下界面。

來讓我們運行一下app,選擇“$”級別奶茶店,再點擊Search按鈕,不出意外,果然崩潰了,為什么呢,因為我們的fetchrequest是從data model獲取的,而從data model獲取的fetchrequest是不可更改的,而我們給他添加了一個判斷條件,所以崩潰了,解決方法很簡單,換一個fetchRequest不就好了,如以下操作:

<pre><code>
override func viewDidLoad() {
super.viewDidLoad()
// fetchRequest = coreDataStack.model.fetchRequestTemplateForName("FetchRequest")
fetchRequest = NSFetchRequest(entityName: "Venue")
fetchAndReload()
}
</code></pre>

我們再來運行下app,選擇“$$”,再點擊“Search”按鈕,結果如果所示:

果然就兩家啊

其他的判斷條件也是只差刪選的斷言就可以進行一樣的刪選功能了:

500米以內,判斷條件如下:

<pre><code>
lazy var walkingDistancePredicate: NSPredicate = {
var pr = NSPredicate(format: "location.distance < 500")
return pr
}()
</code></pre>

有用戶評價,判斷條件如下:

<pre><code>
lazy var hasUserTipsPredicate: NSPredicate = {
var pr = NSPredicate(format: "stats.tipCount > 0")
return pr
}()
</code></pre>
按名字升序排序:
<pre><code>
lazy var nameSortDescriptor: NSSortDescriptor = {
var sd = NSSortDescriptor(key: "name",ascending: true,selector: "localizedStandardCompare:")
return sd
}()
</pre></code>
按距離升序排序:
<pre><code>
lazy var distanceSortDescriptor: NSSortDescriptor = {
var sd = NSSortDescriptor(key: "location.distance",ascending: true)
return sd
}()
</pre></code>

按照價格升序:

<pre><code>
lazy var priceSortDescriptor: NSSortDescriptor = {
var sd = NSSortDescriptor(key: "priceInfo.priceCategory", ascending: true)
return sd
}()
</pre></code>

最后一步就是在TableView選擇方法中初始化刪選條件,像這樣:
<pre><code>
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)!

    switch cell {
        // Price section
    case cheapVenueCell:
            selectedPredicate = cheapVenuePredicate
    case moderateVenueCell:
            selectedPredicate = moderateVenuePredicate
    case expensiveVenueCell:
            selectedPredicate = expensiveVenuePredicate
    case offeringDealCell:
            selectedPredicate = offeringDealPredicate
    case walkingDistanceCell:
            selectedPredicate = walkingDistancePredicate
    case userTipsCell:
            selectedPredicate = hasUserTipsPredicate
    case nameAZSortCell:
            selectedSortDescriptor = nameSortDescriptor
    case nameZASortCell:
            selectedSortDescriptor = nameSortDescriptor.reversedSortDescriptor as? NSSortDescriptor
    case distanceSortCell:
            selectedSortDescriptor = distanceSortDescriptor
    case priceSortCell:
            selectedSortDescriptor = priceSortDescriptor
        
    default:
                println("default case")
    }
        
    cell.accessoryType = .Checkmark
}

</code></pre>

很靈哈~~

異步獲取,在獲取大量數據的時候,可能會使程序無法響應,用戶的操作,這個就很糟糕,如果可以異步獲取的話,那么再獲取數據的同時,用戶還可以進行操作,這就顯的十分友好。
返回 viewcontroller.swift,在viewDidLoad()中添加以下代碼:

<pre><code>
//2
asyncFetchRequest = NSAsynchronousFetchRequest(fetchRequest: fetchRequest){
[unowned self] (result: NSAsynchronousFetchResult! ) -> Void in
self.venues = result.finalResult as! [Venue]
self.tableView.reloadData() }
//3
var error: NSError?
let results = coreDataStack.context.executeRequest(asyncFetchRequest,error: &error)
if let persistentStoreResults = results {
//Returns immediately, cancel here if you want
} else {
println("Could not fetch (error), (error!.userInfo)")
}
</code></pre>

  • //3 這個指的是在完成查詢以后進行的操作,完成數據讀取以后當然是更新tableview。

因為我們進行的是異步讀取,所以剛進入程序時[Venue]為空,這樣初始化TableView的話,會使程序崩潰,最簡單的解決方法就是這樣:

   [Venue] = []

要進行異步讀取還有最后一步要做,打開我們的CoreDataStack.swift文件將
context = NSManagedObjectContext()更改為

  context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)

好的,我們再把程序運行一下,你會發現運行結果與之前一模一樣,這是因為數據數量較少的緣故,當數據規模增大的時候則會顯現出很大的區別。


批量更新,更新的時候我們不能說全部都重新存一遍哈,數量少的時候還好說,數量多的時候這樣做就太糟糕了。
<pre><code>
//1
let batchUpdate = NSBatchUpdateRequest(entityName: "Venue")
//2
batchUpdate.propertiesToUpdate = ["favorite" : NSNumber(bool: true)]
//3
batchUpdate.affectedStores = coreDataStack.psc.persistentStores
//4
batchUpdate.resultType = .UpdatedObjectsCountResultType
//5
var batchError: NSError?
let batchResult = coreDataStack.context.executeRequest(batchUpdate,error: &batchError) as! NSBatchUpdateResult?
if let result = batchResult {
println("Records updated (result.result)")
} else {
println("Could not update (batchError), (batchError!.userInfo)")
}
</code></pre>

  • //1 批量更新其實很簡單哈,先是創建一個NSBatchUpdateRequest和Entity聯系起來。
  • //2 通過batchUpdate.propertiesToUpdate屬性來確定要更新的內容。
  • //3 確定更新的對象,時候影響到數據庫。
  • //4 確定返回內容,我們這里返回更新的個數
一共更新了30條

這一篇的內容大概就是這樣了,總結一下,其實就是通過設定返回類型,和刪選條件來讀取不同的數據,然后還有異步獲取,最后講了批量更新。

喝杯奶茶緩緩~~~~~

初始模板以上傳github:https://github.com/superxlx/BubbleTea
源代碼已上傳github:https://github.com/superxlx/CoreDataTest4

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,829評論 18 139
  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,177評論 4 61
  • 歷史上她是一個傾國傾城的不可多得的美人。 嫁給過李隆基的兒子壽王,后來又轉嫁給了一代帝王李隆基。后來成了一個禍國殃...
    高冷范的逗比閱讀 546評論 0 1
  • 爆裂鼓手 是一部讓你無法停下來去干其他事情的電影, 因為每一幕都太牽動人心了。 緊湊的剪輯,優質的表演,戲劇的沖突...
    第8日影院閱讀 409評論 0 0
  • 觀影,已然成為我生活中必不可少的一件樂事。很多時候,我都覺得,一個人在觀影的同時,也同樣能看見一部分失靈的...
    失靈者閱讀 1,465評論 0 4