程序調(diào)試 (一) —— App Crash的調(diào)試和解決示例(一)

版本記錄

版本號(hào) 時(shí)間
V1.0 2020.01.17 星期五

前言

程序總會(huì)有bug,如果有好的調(diào)試技巧和方法,那么就是事半功倍,這個(gè)專題專門和大家分享下和調(diào)試相關(guān)的技巧。希望可以幫助到大家。

開始

首先看下主要內(nèi)容:

在本教程中,您將了解導(dǎo)致應(yīng)用崩潰的原因以及如何解決該問題。

接著看下寫作環(huán)境:

Swift 5, iOS 13, Xcode 11

應(yīng)用程序崩潰是開發(fā)周期的自然組成部分。 面臨的挑戰(zhàn)是要了解崩潰背后的真正原因并應(yīng)用正確的修補(bǔ)程序,而不僅僅是隱藏崩潰。

在本教程中,您將查看一些崩潰示例,對(duì)其進(jìn)行調(diào)查,了解它們?yōu)槭裁磿?huì)發(fā)生,最后,一勞永逸地修復(fù)它們。

在開始之前,了解有關(guān)Swift的一些詳細(xì)信息非常有價(jià)值,這樣您就可以進(jìn)一步了解遇到的錯(cuò)誤:

  • Swift使用靜態(tài)類型(static typing),這意味著編譯器在編譯時(shí)就知道值的類型。
  • 它確保您在使用變量之前先對(duì)其進(jìn)行初始化。
  • 它還會(huì)通知您可能的nil值,并確保您知道如何在代碼中使用它們。

在修復(fù)項(xiàng)目時(shí),您將對(duì)這些要點(diǎn)有更多的了解。 現(xiàn)在,該忙起來了。

打開入門項(xiàng)目。 您會(huì)發(fā)現(xiàn)一個(gè)名為CrashGallery的項(xiàng)目。

該項(xiàng)目顯示了一些導(dǎo)致應(yīng)用崩潰的常見情況。它是專門為演示這些方案并幫助您了解它們而設(shè)計(jì)的。

gallery展示了三種展品,展示了不同的崩潰場(chǎng)景:

  • 1) Force Unwrapping:顯示某些不正確使用nil值的情況。
  • 2) Weak References:從storyboard中說明用戶界面中的引用鏈,以及如何意外斷開引用鏈并使應(yīng)用崩潰。
  • 3) Invalid Table Updates:顯示與UITableView共同的邏輯差異的示例,它將使您的應(yīng)用程序崩潰。

您將研究所有這些崩潰情況,以了解如何找到它們以及如何進(jìn)行修復(fù)。但是在開始查看崩潰及其原因之前,請(qǐng)花一點(diǎn)時(shí)間回顧一下三個(gè)重要工具,以幫助您在崩潰發(fā)生時(shí)進(jìn)行跟蹤。


Tools to Help You Fix and Resolve Crashes

查明崩潰的原因可能很棘手。幸運(yùn)的是,有一些有用的工具可以使這項(xiàng)工作變得更加容易。本教程的第一步是了解最重要的三個(gè)。

1. Breakpoints

您將介紹的第一個(gè)便捷工具是斷點(diǎn),它使您的應(yīng)用在指定的行上暫停執(zhí)行,因此您可以調(diào)查該點(diǎn)對(duì)象的狀態(tài)。

要在任何行上創(chuàng)建斷點(diǎn),只需在源文件中單擊要停止執(zhí)行的行號(hào)即可。

但是,如果您不確定應(yīng)該看哪行怎么辦?

每當(dāng)從Xcode運(yùn)行的應(yīng)用程序崩潰時(shí),調(diào)試器就會(huì)向您顯示崩潰的行。但是有時(shí)候,這行你并不知道在哪里。對(duì)于這種情況,還有一種方便的斷點(diǎn):異常斷點(diǎn)(exception breakpoint)

發(fā)生崩潰時(shí),異常斷點(diǎn)會(huì)自動(dòng)停止應(yīng)用程序,并向您顯示導(dǎo)致該行的行。現(xiàn)在,這并不總是您需要解決的問題。崩潰可能是由于之前幾行的錯(cuò)誤所致,但是該行在應(yīng)用中顯示“嘿……我無法繼續(xù)進(jìn)行”。

要添加異常斷點(diǎn),請(qǐng)打開Debug navigator,然后單擊導(dǎo)航器左下角的+。從結(jié)果菜單中選擇Exception Breakpoint…。單擊結(jié)果對(duì)話框外的任意位置以設(shè)置斷點(diǎn)。

注意:異常斷點(diǎn)是由Objective-C運(yùn)行時(shí)中發(fā)生的錯(cuò)誤觸發(fā)的,這在大多數(shù)情況下是UIKit內(nèi)部的錯(cuò)誤。大多數(shù)Swift崩潰都會(huì)使調(diào)試器停止在您要查找的實(shí)際行上。

2. Console Log

控制臺(tái)日志位于Xcode窗口的底部。 該應(yīng)用運(yùn)行時(shí),它將顯示大量有用的日志。 每當(dāng)您的應(yīng)用崩潰時(shí),您都會(huì)發(fā)現(xiàn)一條日志消息,其中包含有關(guān)崩潰性質(zhì)的信息,無論是索引超出范圍的異常,nil引用還是其他。

該日志還包含有關(guān)警告的信息,因此即使您的應(yīng)用程序沒有崩潰也要引起注意。 它可能會(huì)突出顯示可以幫助您改善應(yīng)用程序的內(nèi)容。

應(yīng)用未運(yùn)行時(shí),此窗口將完全為空。 當(dāng)您運(yùn)行應(yīng)用程序時(shí),它將開始顯示日志。

3. Variables View

用于調(diào)查崩潰的第三個(gè)有價(jià)值的工具是Variables View。 與控制臺(tái)日志類似,當(dāng)應(yīng)用程序未運(yùn)行時(shí),它將完全為空;但是,當(dāng)應(yīng)用程序執(zhí)行時(shí),它將保持為空。

當(dāng)您暫停執(zhí)行時(shí),該視圖將僅顯示當(dāng)前作用域中變量的值,這與斷點(diǎn)并存。

控制臺(tái)日志還顯示變量的值,但是Variables View更直觀,并向您顯示所有變量,而不僅僅是一個(gè)。 在許多情況下,它很有用,因此最好對(duì)兩者都熟悉。

Console Log printing the value of a variable that is also present in the Variables View.
Variables View can show more than just text information. It can show the visual content of a UI element.

現(xiàn)在,您已經(jīng)知道修復(fù)該損壞的應(yīng)用程序,構(gòu)建和運(yùn)行入門應(yīng)用程序所需的工具,并了解第一個(gè)展覽。


The Infamous nil

Swift引入了可選參數(shù)(optionals),這意味著對(duì)象或表達(dá)式可能具有值,也可能沒有值。 您不能假設(shè)自己將永遠(yuǎn)擁有值。 這是您的應(yīng)用崩潰的最常見原因。

在第一個(gè)exhibit中,您會(huì)看到其中的一些情況,但是最好先了解Xcode所提供的功能,以幫助您確定崩潰的位置,發(fā)生的情況以及原因。 相當(dāng)多的偵探工作。


Exhibit A: Dark Force – Force Unwrapping

構(gòu)建并運(yùn)行該應(yīng)用程序,然后在圖庫屏幕中打開標(biāo)題為Force Unwrapping的第一項(xiàng)。

此屏幕的任務(wù)是計(jì)算頂部寫的數(shù)字總和。 頂部的文字視圖包含電視節(jié)目Lost中輸入的數(shù)字,并用逗號(hào)分隔。

當(dāng)您點(diǎn)擊Calculate按鈕時(shí),數(shù)字總和將顯示在屏幕上。 試一試。

太好了,它可以按您的預(yù)期工作。 現(xiàn)在,對(duì)其進(jìn)行處理,并在數(shù)字序列的末尾添加,two

點(diǎn)擊Calculate看一下發(fā)生了什么...,程序崩潰了

崩潰位于第49行的ForceUnwrappingViewController.swift中。看看Xcode向您顯示的內(nèi)容–觸發(fā)崩潰的行上有一個(gè)紅色突出顯示。

控制臺(tái)日志包含有關(guān)崩潰的信息,并且Variables View顯示了calculateSum(items :)范圍內(nèi)的itemfinalValue的值。

item的值為“ two”,因此當(dāng)您將其轉(zhuǎn)換為Int時(shí),它會(huì)失敗,并給出nil值。 強(qiáng)制解包 操作符導(dǎo)致了崩潰。

1. Proving Your Case

不要把上述猜當(dāng)成事實(shí); 質(zhì)疑它,并確保真正是導(dǎo)致崩潰的原因。 修復(fù)崩潰問題后,您并不想反復(fù)嘗試。 您希望110%確定要解決的問題。

要測(cè)試您的理論,請(qǐng)?jiān)诳刂婆_(tái)日志中鍵入以下命令:

po Int(item)

在表達(dá)式之前輸入的po命令代表打印對(duì)象(print object),這是一個(gè)LLDB命令,用于打印對(duì)象的描述。 您也可以使用p,但控制臺(tái)中的結(jié)果看起來會(huì)略有不同。

控制臺(tái)輸出將為nil

所以Int(item)nil,執(zhí)行po Int(item)時(shí)! 您會(huì)獲得一些其他信息。

此結(jié)果與崩潰上記錄的錯(cuò)誤相同,因此您對(duì)崩潰的來源絕對(duì)正確。

可是等等! 其他值如何工作?

在導(dǎo)致崩潰的同一行上添加一個(gè)斷點(diǎn),然后重新啟動(dòng)應(yīng)用程序。 在計(jì)算總和之前,請(qǐng)記住先寫,two

斷點(diǎn)上item的值為4,并且Int(item)的結(jié)果給出一個(gè)值而不是nil

2. Finding the Right Solution

Int(_ :)item的值為4時(shí)有效,但在其值為two時(shí)無效。 換句話說,當(dāng)值是帶有數(shù)字的字符串而不是帶有字母的字符串時(shí),即使它們構(gòu)成數(shù)字的名稱,它也可以工作。

要解決此崩潰,請(qǐng)?jiān)?code>calculateSum(items :)中替換以下代碼行:

finalValue += Int(item)!

使用下面的代碼

if let intValue = Int(item) {
  finalValue += intValue
}

上面的代碼在使用Int(item)之前檢查其結(jié)果是否為nil,以防崩潰。

通過單擊藍(lán)色箭頭禁用斷點(diǎn),它將變?yōu)榘胪该鞯乃{(lán)色。 在數(shù)字之后的文本字段中構(gòu)建并運(yùn)行并添加所需的任何類型的文本。

它不再崩潰,但是否已完全修復(fù)? 下面不添加數(shù)字,請(qǐng)刪除最后一個(gè),然后重試。

該應(yīng)用程序在58行的ForceUnwrappingViewController.swift中再次崩潰。

日志相關(guān)信息如下所示:

Could not cast value of type 'Swift.String' (0x7fff879c3f88) to 'Swift.Int' (0x7fff879c1e48).

崩潰行強(qiáng)制將結(jié)果強(qiáng)制轉(zhuǎn)換為Int,而您提供的值是String。 這意味著valueToShownil,當(dāng)您強(qiáng)制對(duì)其進(jìn)行拆包時(shí),該應(yīng)用程序崩潰,類似于上面已修復(fù)的崩潰。

僅當(dāng)總數(shù)大于100時(shí),calculateSum(items :)才會(huì)顯示總和。否則,消息應(yīng)為Sum is too low

這是一個(gè)簡(jiǎn)單的解決方法。 用以下代碼塊替換showResult(result :)中的代碼:

if let intValue = result as? Int {
  sumLabel.text = "\(intValue)"
} else if let stringValue = result as? String {
  sumLabel.text = stringValue
}

在這里,您檢查是否可以將result強(qiáng)制轉(zhuǎn)換為Int,然后創(chuàng)建其值的字符串并將其添加到label中。 如果可以將其強(qiáng)制轉(zhuǎn)換為字符串,則按原樣使用該值。

構(gòu)建并運(yùn)行。 當(dāng)總數(shù)低于100時(shí),您會(huì)看到錯(cuò)誤消息Sum is too low


Exhibit B: Weak Grip — Weak References

您要解決的第二個(gè)崩潰涉及一種不尋常的顯示和隱藏視圖的方法。

Weak References屏幕是一個(gè)包含兩個(gè)步驟的簡(jiǎn)單表單,其中,只有第一個(gè)問題的答案為yes時(shí),第二步才處于激活狀態(tài)。

注意:除了此應(yīng)用程序中顯示的方法以外,還有很多方法可以實(shí)現(xiàn)相同的結(jié)果。 目的是顯示導(dǎo)致崩潰的方案,而不是設(shè)計(jì)出能正常工作的表單。

當(dāng)您關(guān)閉開關(guān)時(shí),第二個(gè)問題消失了,但是當(dāng)您再次將其打開時(shí)…發(fā)生了崩潰。

該應(yīng)用程序在WeakReferencesViewController.swift37行中崩潰了。

WeakReferencesViewController具有三個(gè)項(xiàng)目:

  • 1) 到stackViewIBOutlet
  • 2) 第二個(gè)QuestionViewIBOutlet
  • 3) IBActionswitchValueChanged(_ :),在其中您更改開關(guān)的值以刪除secondQuestionView或?qū)⑵渲匦绿砑拥?code>stackView的底部。

有兩種方法可以弄清Xcode為什么顯示nil:從Variables View中瀏覽值,或檢查從控制臺(tái)日志崩潰行中找到的兩個(gè)變量的值。

從調(diào)試器的輸出中可以看出,secondQuestionView的值為nil,但是為什么呢? 在switchValueChanged(_ :)的第一行上添加一個(gè)斷點(diǎn),然后重新啟動(dòng)應(yīng)用程序以開始調(diào)查。

構(gòu)建并運(yùn)行。

當(dāng)您關(guān)閉開關(guān)時(shí),secondQuestionView不會(huì)為nil。但是,當(dāng)視圖消失后再次打開時(shí),它已經(jīng)為nil

1. Understanding the Crash

這樣做的原因是由于UIKit中的引用鏈(reference chain)。每個(gè)視圖都強(qiáng)引用(strong reference)其中顯示的子視圖。只要secondQuestionView在屏幕上的視圖層次結(jié)構(gòu)中,就會(huì)有對(duì)其的強(qiáng)引用。

因此,當(dāng)您從第二個(gè)ViewView的superview中刪除了第二個(gè)QuestionView時(shí),您就打破了連接。并查看secondQuestionViewIBOutlet定義,您會(huì)發(fā)現(xiàn)它被標(biāo)記為weak。因此,它從內(nèi)存中釋放,并且其引用更改為nil,因?yàn)闆]有人持有它以防止這樣做。

一旦從secondQuestionView聲明中刪除了weak關(guān)鍵字,崩潰將消失。您可以對(duì)stackView進(jìn)行相同的操作,以防萬一,但是由于從不從父視圖中移除stackView,因此它對(duì)崩潰沒有影響。

刪除weak關(guān)鍵字,然后構(gòu)建并運(yùn)行以再次嘗試該場(chǎng)景。

您會(huì)看到該表格現(xiàn)在可以正常工作了。 該視圖出現(xiàn)并根據(jù)需要消失。


Exhibit C: Unexpected Updates — Invalid Table Updates

第三次崩潰與之前的崩潰略有不同。 更多的是數(shù)據(jù)不匹配。

在圖庫屏幕上打開第三個(gè)項(xiàng)目,稱為Invalid Table Updates,現(xiàn)在開始研究下。

該屏幕具有一個(gè)包含四個(gè)單元格的表格視圖。 每個(gè)單元格上都有其編號(hào)。 右上角還有一個(gè)小按鈕,可以添加更多單元格。

繼續(xù)并按該按鈕。 如您所料,發(fā)生了崩潰。 但是...哪行崩潰了? 日志中有什么?

Xcode在第32行的AppDelegate.swift中停止。

將異常斷點(diǎn)添加到您的項(xiàng)目,然后構(gòu)建并運(yùn)行以查看差異。

這次,Xcode在第37行的InvalidTableUpdatesViewController.swift中停止了。日志為空,并且沒有提供任何信息,因?yàn)閿帱c(diǎn)在異常發(fā)生之前就已停止。 與之前的崩潰相比,這是另一種崩潰。

當(dāng)您按繼續(xù)按鈕時(shí),Xcode將返回到AppDelegate.swift中的類聲明行,并且日志將包含崩潰信息。

日志包含有關(guān)崩潰的信息以及崩潰發(fā)生時(shí)的堆棧跟蹤(stack trace)信息。 在大多數(shù)情況下,從Xcode進(jìn)行調(diào)試并啟用異常斷點(diǎn)時(shí),不需要堆棧跟蹤信息。 看一下崩潰信息。

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to insert row 4 into section 0, but there are only 4 rows in section 0 after the update.

1. A Wider View of the Problem

在檢查崩潰本身之前,您應(yīng)該了解addPressed()的用途。這三行執(zhí)行以下操作:

  • 1) 在section 0的最后一行之后創(chuàng)建一個(gè)IndexPath對(duì)象。索引4代表第五項(xiàng),因?yàn)樗饕龔?code>0開始。
  • 2) 告訴tableViewnewIndex處插入新行。
  • 3) 將新行添加到itemsList數(shù)據(jù)源數(shù)組。

首先,看一下流程:這是合理的,也是正確的。但是Xcode只是告訴您,事實(shí)并非如此。那有什么問題呢?

2. Narrowing Down the Problem

異常斷點(diǎn)在第二行停止,因此該應(yīng)用未將新行添加到itemsList。此時(shí),這似乎是一個(gè)簡(jiǎn)單的解決方法-將新項(xiàng)目添加到itemsList中,然后再將其插入tableView中。它有助于更??多地了解導(dǎo)致崩潰的行。

確保已啟用異常斷點(diǎn),然后生成并運(yùn)行并再次打開同一屏幕。

打開InvalidTableUpdatesViewController.swift并在導(dǎo)致崩潰的第37行和第44行(即tableView(_:numberOfRowsInSection :)的返回)上添加斷點(diǎn)。按添加按鈕,使應(yīng)用程序在第一個(gè)斷點(diǎn)處停止,然后按繼續(xù)。現(xiàn)在,查看左側(cè)的調(diào)用堆棧:

請(qǐng)注意,insertRows(at:with :)在內(nèi)部對(duì)tableView(_:numberOfRowsInSection :)進(jìn)行了調(diào)用,以檢查itemsList的新大小。 由于itemsList尚未更新,因此tableView找不到添加到其中的任何東西,這使其處于不一致狀態(tài)。

換句話說,您告訴tableView有一個(gè)新項(xiàng)目,但是tableView卻沒有發(fā)現(xiàn)itemsList增長(zhǎng)了。

這證明了table view的行為。 將代碼行添加到itemList的其他兩行之間。 addPressed()現(xiàn)在應(yīng)如下所示:

@IBAction func addPressed() {
  let newIndex = IndexPath(row: itemsList.count, section: 0)
  itemsList.append((itemsList.last ?? 0) + 1)
  tableView.insertRows(at: [newIndex], with: .automatic)
}

這將在更新視圖之前更新數(shù)據(jù)源。 構(gòu)建并運(yùn)行,然后按添加按鈕以查看是否一切正常:


Assertions

斷言是手動(dòng)觸發(fā)的崩潰,您可以將其插入自己的代碼中。顯而易見的問題是:為什么要編寫代碼以使自己的應(yīng)用程序崩潰?

這是一個(gè)很好的問題。不管看起來多么不合邏輯,您都會(huì)立刻理解為什么這樣做會(huì)有所幫助。

想象一下,您正在編寫一段復(fù)雜的代碼,并且邏輯中有些流程沒有人可以到達(dá),因?yàn)榈竭_(dá)它們意味著發(fā)生了致命的錯(cuò)誤。

這些情況非常適合斷言。他們會(huì)幫助您或其他使用您代碼的人發(fā)現(xiàn)開發(fā)過程中無法正常工作。

1. Writing Your Own Reusable Code

編寫framework框架也是斷言可能有用的一個(gè)很好的例子。如果其他開發(fā)人員向您的框架提供了不合理的輸入而效果卻不理想,則可以引起一個(gè)斷言。

ForceUnwrappingViewController.swift中的一個(gè)方便示例。如果沒有將result強(qiáng)制轉(zhuǎn)換為IntString,則showResult(result :)不會(huì)發(fā)生任何事情,并且使用您代碼的人都不會(huì)立即知道發(fā)生了什么。當(dāng)然,他們做錯(cuò)了什么,但是如果代碼足夠聰明地告訴他們什么,那豈不是很棒嗎?

要嘗試,請(qǐng)?jiān)?code>showResult(result :)的末尾添加以下代碼塊:

else {
  assertionFailure("Only Int or Strings are accepted in this function")
}

如果result不是IntString,則會(huì)提出一個(gè)斷言。 在calculatePressed(_ :)的末尾添加以下代碼行以查看其工作方式:

showResult(result: UIView())

在這里,您向showResult(result :)發(fā)送了一個(gè)非常意外的值……一個(gè)UIView

構(gòu)建并運(yùn)行,打開Force Unwrapping屏幕,然后按Calculate按鈕。

您的應(yīng)用在第65行的ForceUnwrappingViewController.swift中崩潰了。

不出所料,崩潰行是斷言調(diào)用的地方,但您尚未完全回答問題。 如果開發(fā)人員無法涵蓋所有情況,崩潰的代碼是否應(yīng)該放在AppStore的最終應(yīng)用中?

該問題的答案是:沒關(guān)系。

這些斷言確實(shí)存在于您的最終產(chǎn)品中,但好像根本就沒有。

斷言僅在您的應(yīng)用程序在調(diào)試debug配置下構(gòu)建時(shí)起作用。 在發(fā)布release配置下,斷言不會(huì)執(zhí)行任何操作,這是在AppStore上載應(yīng)用程序時(shí)將如何構(gòu)建它的方法。

想自己看看嗎? 您將在下一步中進(jìn)行嘗試。

2. Changing Your Build Configuration

單擊Xcode窗口左上角的CrashGallery目標(biāo)以進(jìn)行嘗試。 從下拉菜單中選擇Edit Scheme,然后從新窗口的左側(cè)選擇Run,然后選擇Build Configuration中的Release

構(gòu)建并運(yùn)行,然后再次按Calculate按鈕。

沒有崩潰,沒有斷言。 它正常工作。 當(dāng)您的代碼獲得意外的值時(shí),它什么也不做,因此此步驟無效。

但也請(qǐng)注意,發(fā)行版release配置并非用于調(diào)試。 您會(huì)發(fā)現(xiàn),在選擇Release的情況下進(jìn)行調(diào)試時(shí),Xcode的運(yùn)行情況不會(huì)達(dá)到預(yù)期。 它可能顯示執(zhí)行錯(cuò)誤的行,Variables View可能不顯示任何值,或者控制臺(tái)日志可能不評(píng)估您打印的表達(dá)式。

如果要評(píng)估性能,而不是代碼跟蹤和調(diào)試,請(qǐng)使用此配置。

斷言是一個(gè)方便的工具,可以幫助您的開發(fā)人員或其他人在遺忘之前修復(fù)它們。 但是請(qǐng)不要過度使用它們,因?yàn)樗鼈儠?huì)變得煩人而不是幫助。

注意:使用preconditionFailure(_:file:line :)fatalError(_:file:line :)而不是assertionFailure(_:file:line :)可以使您的應(yīng)用在release配置下崩潰。

后記

本篇主要講述了App Crash的調(diào)試和解決示例,感興趣的給個(gè)贊或者關(guān)注~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 因?yàn)橐Y(jié)局swift3.0中引用snapKit的問題,看到一篇介紹Xcode8,swift3變化的文章,覺得很詳細(xì)...
    uniapp閱讀 4,484評(píng)論 0 12
  • 淚化馬嵬風(fēng), 一場(chǎng)春夢(mèng)空。 遺留千古恨, 誰與問蒼穹。
    明月清泉_e47b閱讀 178評(píng)論 4 4
  • 春盛秋衰自尋常,何用添詞助悲喜。 人生漸行如夢(mèng)昏,一生多在無知中。
    明心123閱讀 252評(píng)論 0 3
  • 對(duì)我來說時(shí)代沒有太多意義 自己就是朵奇葩 貼不上時(shí)代的標(biāo)簽 這個(gè)年代獨(dú)生子女太多 對(duì)親情的理解會(huì)有所怪異 我算一個(gè)...
    L丶Ctrl閱讀 328評(píng)論 0 0
  • 或許你會(huì)覺得, 如今社會(huì)冷漠漫延, 冰冷總是令人寒顫。 可是, 你是否考慮過自己的內(nèi)心是否已冰封。 若有光芒灑下,...
    簡(jiǎn)萌璽閱讀 164評(píng)論 0 1