Effective Objective-C 2.0 無廢話精簡篇

1. 了解 Objective-C 語言的起源

Objective-C 語言使用”消息結構”而非”函數調用”.Objective-C 語言由 Smalltalk演化而來,后者是消息類型語言的鼻祖.編譯器甚至不關心接收消息對象的何種類型.接收消息的對象問題也要在運行時處理,其過程叫做”動態綁定”.
Objective-C為 C 語言添加了面向對象特性,是其超類. Objective-C 使用動態綁定的消息結構,也就是說,在運行時才會檢查對象類型.接收一條消息后,究竟應執行何種代碼,有運行期環境而非編譯器決定.理解 C 語言的核心有助于寫好 Objective-C 程序.尤其是掌握內存模型與指針.

2. 在類的頭文件中盡量少引用其他頭文件

Objective-C 語言編寫類的標準行為:以類名做文件名,分別闖將兩個文件,有文件后綴用. h,實現文件后綴用. m.
在開發中有時候我們會在. h 文件中引入很多用不到的內容,這當然會增加編譯時間.除非有必要,否則不要引入頭文件,一般來說,某個類的頭文件中使用向前聲明來體積別的類,并在實現文件中引入哪些類的頭文件,這樣做可以盡量降低類之間的耦合.有時無法使用前聲明,比如要聲明某個類遵循意向協議,這種情況下,盡量把 “該類遵循某協議”的這條聲明移至 class=continuation 分類中,如果不行的話,就把協議單獨存放在一個頭文件中,然后將其引入.

3. 多用字面量語法,少用與之等價的方法
NSArray *arr = [NSArray arrayWithObjects:@"num1",@"num2",@"num3", nil];
NSArray *arr = @[@"num1",@"num2",@"num3”];

字面量語法創建字符串,數組,數值,字典.與穿件此類對象的常規方法相比,這么做更加簡明扼要.

注意事項:

  • 除了字符串以外,所創建的類必須屬于 Foundation 框架才行,如果自定義了這些類的子類,則無法用字面量語法創建其對象.
  • 穿件的數組或字典時,若值有 nil, 則會拋出異常.因此,務必確保值中不含 nil.
4. 多用類型常量,少用# deine 預處理指令

不要用預處理指令定義常量,這樣定義出來的常量不含類型信息,編譯器只會在編譯前根據執行查找與替換操作,即使有人重新定義了常量值,編譯器也不會產生井道信息,這將導致應用程序常量值不一致.

static NSString *const PersonConstant = @"PersonConstantStr” ;

但是我個人認為其實,還是#define用的多, 開發避免不了使用 pch文件. 如果有強迫癥的同學,定義常量就想使用 staitc,extren,const這些關鍵字.那我建議新建一個專門存放這些常量的類,然后在 pch 中導入這個類.

  • static 修飾符意味著該變量盡在定義此變量的單元中可見
  • extern 全局變量
Person.h
#import <Foundation/Foundation.h>
static NSString *const PersonConstant;
@interface Person : NSObject
@end

Person.m
#import "Person.h"
static NSString *const PersonConstant = @"PersonConstantStr";
@implementation Person
@end

.pch
#define DefineStr @"DefineStr"
#import "Person.h"
#endif
5. 用枚舉表示狀態,選項,狀態碼

應該用枚舉來表示狀態機的狀態,傳遞給方法的選項以及狀態碼等值,給這些值起個易懂的名字

enum PersonEnum{
    PersonEnumNum1,
    PersonEnumNum2,
    PersonEnumNum3,
};
typedef enum PersonEnum PersonState;
6. 理解屬性這一概念

屬性是 Objective-C 的一項特性,用于封存對象中的數據.
屬性特質:原子性 讀寫權限
內存管理語義

  • assign 這是方法只會執行針對純量類型(CGFloat,NSInteger)的簡單賦值操作
  • strong 此特質表明該屬性定義一種擁有關系,為這種屬性設置新值時,這只方法會先保存新值,并釋放舊值
  • weak 此特質表明屬性定義了一種”非擁有關系”,為這種屬性設置新值是,設置方法既不保留新值,也不釋放舊值.此特質同 assign 類似,然而在屬性所指對象遭到摧毀時,屬性值會清空
  • unsafe_unretainde 此特質與 assign 相同,它適用于對象類型,該特質表達一種"非擁有關系”,當目標對象遭到摧毀時,屬性不會自動清空,因為它是不安全的,這一點與 weak 的區別
  • copy 此特質所表達的所屬關系與 strong 類似,然而設置方法并不保留新值,而是將其拷貝,多用于 NSString.
7. 在對象內部盡量直接訪問實例變量

直接訪問實例變量的速度比較快,因為不經過 Objective-C 方法派發,編譯器所生成的代碼會直接訪問保存催下實例量的那塊內存.
直接訪問實例變量時,不會調用設置方法,這就繞過了相關屬性所定義的內存管理語義.

8. 理解"對象等同性”這一概念

根據等同性來比較對象是一個非常有用的功能,不過,按照==操作符比較出來的結果未必是我們想要的,因為該操作比較的事兩個指針本身,而不是其所指的對象.應該使用 NSObject 協議中的聲明的”isEqual”方法來判斷兩個對象的等同性,一般來說兩個類型不同的對象總是不相等的.直接比較字符串的時候 isEqual 比 isEqualToString慢,因為前者還要執行額外步驟.

9. 以"類族模式"隱藏實現細節

“類族”是一種很用用的模式,可以隱藏抽象基類背后實現的細節. 這是一種”工廠模式”.比如iOS 用戶界面框架 UIKit 中就有一個名為 UIButton 的類.想創建按鈕,需要調用下面這個類方法.
+(UIButton*)buttonWithType:(UIButtonType)type;
我到是認為,作者想告訴我我們要好好封裝代碼,這個地方沒啥好說的.

10. 在既有類中使用關聯對象存放自定義數據

有時需要在對象中存放相關信息,這是我們通常會從對象所屬的類中繼承一個子類,然后改用這個子類對象.然而并非所有情況下都這么做,有時候類的實例可能是由某種機制所創建的,而開發者無法令這種機制創建出自己所寫的實例. Objective-C 中有意向強大的特性可以解決問題,這就是關聯對象.

11. 理解objc_msgSend的作用

用Objetive-C的術語來說,這叫做“消息傳遞”。這里說的是運行時。

12. 理解消息轉發機制

當對象接收到無法解讀的消息后,就會啟動消息轉發機制,程序員可經此過程告訴對象應該圖和處理未知消息。這里說的是運行時。

13. 用方法調配技術調試黑盒方法

運行期間,可以向類中新增或替換選擇子所對應的方法實現。
使用另一份實現來替換原有的方法實現,這道工序叫做方法調配,開發者常用此技術想原有實現中添加新功能。
一般來說,只有調試程序的時候才需要運行期修改方法實現,這種做法不易濫用。這里說的是運行時。

14. 理解類對象的用意

每個Objective-C對象實例都是指向某塊內存數據的指針,如果把對象所需的內存分配到棧上編譯器就會報錯
每個對象結構體的首個成員是Class類的變量,該變量定義了對象所屬的類,通常稱為isa指針。

typedef struct objc_class *class
struct objc_class{
    Class isa;
    Class super_class;
    const char* name;
    long version;
    long info;
    long instance_size;
    struct objc_ivar_list *ivars;
    struct objc_method_list *ivars;
    struct objc_cache *cache;
    struct objc_protocol_list protocols;
}

此結構體存放類的元數據,例如類的實例實現了幾個方法,具備多少個實例變量等信息。次結構體的首個變量也是isa指針,這說明Class本身亦為Objctive-C對象。結構體里還有個變量叫做super_class,它定義本類的超類,類對象所屬的類型(isa指針所指向的類型)是另外一個類,叫做元類,用來標書類本身所具備的元數據。類方法就定義于此處,因為這些方法可以理解成類對象的實例方法,每個類僅有一個類對象,每個類對象僅有一個與之相關的元類。 (元數據,就是這個類的數據。)
isKindOfClass:能夠判斷對象是否為某類或其派生類的實例
isMemberOfClass: 能夠判斷出對象是否為某個特定類的實例

15. 用前綴避免命名空間沖突

這個沒啥可說的

16. 提供全能初始化方法

這個沒啥可說的

17. 實現description方法

調試程序時經常需要打印并查看對象信息。description 很實用。

Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property(nonatomic,assign)int age;
@property(nonatomic ,copy)NSString* name;
@end

Person.m
#import "Person.h"
@implementation Person
- (NSString *)description
{
    return [NSString stringWithFormat:@"name %@ , age %d", self.name, self.age];
}
@end

description寫出想要的屬性, 在ViewController打印 Person 對象 Person的相關屬性就會出現在控制臺。

18. 盡量使用不可變對象

這個沒啥可說的

19. 使用清晰而協調的全名方式

這個沒啥可說的

20. 為私有方法名加前綴

這個沒啥可說的

21. 理解Objective-C錯誤模型

NSError的用法更加靈活,因此經由此對象,我們可以把導致錯誤的原因匯報給調用者。

  • NSError domain(錯誤范圍,其類型為字符串)
    錯誤發生的范圍,也就是產生錯誤的根源,通常用一個特有的全局變量來定義,比方說 “處理URL子系統”從URL的解析獲取數據時如果出錯了,那么就會使用NSURLErrorDomain來表示錯誤范圍
  • Error code(錯誤碼,其類型為整數)
    獨有的錯誤代碼,用以指明在某個范圍內具體發生了何種錯誤。某個特性范圍內可能會發生一系列相關錯誤,這些錯誤情況通常采用enum來定義。例如,當HTTP請求出錯時,可能會把HTTP狀態碼設為錯誤碼
  • User info(用戶信息,其類型為字典)
    有關錯誤的額外信息,其中或許包含一段“本地化的描述”或許還含有導致錯誤發生的另外一個錯誤,經由此種信息,可將相關錯誤串成一條“錯誤鏈”
@try {
        NSString *str = @"wotaxiwa";
        NSString *strErr = [str substringFromIndex:100];
        NSLog(@"%@",str);
    } @catch (NSException *exception) {
       
        NSLog(@"ERROR:     %@",exception);
    } @finally {
        NSLog(@"%s",__func__);
    }

如果出現exception,異常后面的代碼將不會繼續執行

22. 理解NSCopying協議
  • copy方法實際上是調用 -(id)copyWithZone:(NSZone*)zone; 實現copy操作, 如果想對自己的類支持拷貝并且做額外操作,那就要實現NSCopying協議此的方法。
    為何出現NSZone呢,以前開發程序時,會據此把內存分成不用的區,而對象會創建在某個區。 現在不用了,每個程序只有一個區:“默認區”,所以不用擔心zone參數。
    copy方法由NSObject實現,該方法只是以默認區為參數調用。

  • mutableCopy方法實際上是調用 -(id)mutableCopyWithZone:(NSZone*)zone; 實現mutableCopy操作

copy mutableCopy 我認為就是原型設計模式不明白的同學請看這個網頁

涉及到深拷貝和淺拷貝的知識不明白的同學請看這篇博客

23. 通過委托與數據協議進行對象間通信

這一條說的就是delegate(代理設計模式)。但是并沒有說delegate的循環引用的問題,在使用代理聲明一個 @property的時候,記得用weak。

@protocol PersonDelegate <NSObject>
-(void)areYouPerson;
@end

@property (nonatomic,weak)id<PersonDelegate> pd;
24. 將類的實現代碼分散到便于管理的數個分類之中

這個沒啥可說的

25. 總是為第三方類的分類名稱加前綴

這個沒啥可說的

26. 勿在分類中聲明屬性

正常的分類是不可以聲明屬性的,但是從技術上說,分類里可以用runtime聲明屬性。

#import <objc.runtime.h>
static const char *kFriendsPropertyKey = “kFriendsPropertyKey”;
@implementation EOCPerson(Friendship)
-(NSArray*)friends{
    return objc_getAssociatedObject(self,kFriendsPropertyKey);
}

-(void)setFriends:(NSArray*)friends{
    objc_setAssociateObject(self.kFriendsPropertyKey,friends,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

這樣做可行,但是不太理想,要吧相似的代碼寫很多遍。而且容易出現Bug,可以使用class-continuation實現分類添加屬性。

27. 使用class-continuation分類隱藏實現細節

class-continuation分類和普通的分類不同,它必須在其所接續的那個類的實現文件里。其重要之處在于,這是唯一能生命實例變量的分類,而且此分類沒有特定的實現文件,其中的方法應該定義在類的主實現文件里。與其他分類不用,“class-continuation分類”沒有名字,比如,有個類叫做EOCPerson,其“class-continuation分類”寫法如下:

@interface EOCPerson()
@end

我們在創建一個類的時候系統已經自動幫我們在,m中實現了,以下代碼都應該很熟悉吧。

#import "ViewController.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
  
}
@end

沒錯它就是 class-continuation分類,在此代碼之間可以添加屬性,修改屬性。

@interface ViewController ()
@end

使用class-continuation分類的好處

  • 可以向類中新增實例變量。
  • 如果類中的主接口聲明為只讀,可以再類內部修改此屬性。
  • 把私有方法的原型文件生命在”class-continuation分類”里面。
  • 想使類遵循的協議不為人知,可以用“class-continuation分類”中聲明。
28. 通過協議提供匿名對象

這個沒啥可說的
說的就是這句話

@property (nonatomic,weak)id<PersonDelegate> pd;
29. 理解引用計數

理解引用計數,方便于了解iOS的內存管理。不過現在都是ARC的時代了。
引用計數機制通過可以遞增遞減的計數器來管理內存。對象創建好之后,其保留計數至少為1。若保留計數為正,則對象繼續存活。當保存計數降為0,對象就被銷毀了。
在對象生命期中,其余對象通過引用來保留或釋放此對象。保留與釋放操作分別會遞增及遞減保留計數。

30. 以ARC簡化引用計數

使用ARC要計數,引用計數實際上還是要執行的,只不過保留與釋放操作現在由ARC自動為你添加。由于ARC會自動執行retain、release、autorelease等操作,所以直接在ARC下調用這些內存管理方法是非法的。
ARC在調用這些方法時,并不用過普通的Objective-C消息派發機制,二十直接調用其底層C語言版本,這樣做性能更好,直接調用底層函數節省很多CPU周期。
雖然有了ARC之后無需擔心內存管理問題,但是CoreFoundation對象不歸ARC管理,開發者必須適時調用CFRetain/CFRelease.

31. 在dealloc方法中只釋放引用并解除監聽

當一個對象銷毀的時候會調用dealloc方法,但是當開銷較大或系統內稀缺資源則不再此列,像是文件描述、套接字、大塊內存等都屬于這種資源,通常對于開銷較大的資源實現一個方法,當程序用完資源對象后,就調用此方法。這樣一來,資源對象的生命期就變得明確了。

32.編寫“異常安全代碼”時留意內存管理問題

圖不重要看字。
圖片中的情景是MRC。現在已經是ARC時代了。但是在使用@try 的時候也要注意,在捕獲到異常的時候@try{}中的語句執行到異常代碼的那一行后不在執行,然后把異常拋給@catch。當然@finally是一定要執行的。
如下 并沒有執行代碼中的NSLog(@"%@",array);

    @try {
        NSArray *array = @[@"a",@"b",@"c"];
        NSString *str_arr = array[4];
        NSLog(@"%@",array);

    } @catch (NSException *exception) {
        NSLog(@"%@",exception);
    } @finally {
        NSLog(@"%s",__func__);
    }
33. 以弱引用避免保留環
  • unsafe_unretained 語義同assign等價。然而assign通常用于int、float、結構體等。unsafe_unretained多用于對象類型。
  • weak 與 unsafe_unretained 作用相同,然而只要系統把屬性回收,屬性值為nil。
    推薦使用weak,畢竟是ARC時代的產物,而且用的人也很多。
34. 以“自動釋放池塊”降低內存峰值
    @autoreleasepool {
        <#statements#>
    }

    for (int i = 0; i < 1000000; i++) {
        @autoreleasepool {
            NSNumber *num = [NSNumber numberWithInt:i];
            NSString *str = [NSString stringWithFormat:@"%d ", i];
            [NSString stringWithFormat:@"%@%@", num, str];
           
            if(lagerNum-1 == i)
            {
                NSLog(@"end");
            }
        }
    }


由此可見我們合理運用自動釋放池,可降低應用程序的內存峰值。

35. 用“僵尸對象"調試內存管理問題

向已回收的對象發送消息是不安全的。
在左上角標題欄找到項目單擊后選擇 Edit scheme 勾選圖中檢測僵尸對象


36. 不要使用retainCount

這個沒啥可說的
MRC時代的產物,忽略

37. 理解”塊“這一概念

這里其實就是在說block,復習一下block的語法吧
返回值類型(block名稱)(參數)
需要注意的是 定義block時候,其所占內存區域是分配在棧中的,快只在定義它的那個范圍內有效。block所使用的整個內存區域,在編譯期已經完全確定,因此,全局block可以生命在全局內存里,而不需要在每次用到的時候于棧中創建,另外,全局block的拷貝是個空操作,因為全局block絕不可能為系統所回收,這種block實際上相當于單例。

38. 為常用的塊類型創建typedef

這個沒啥可說的

typedef <#returnType#>(^<#name#>)(<#arguments#>);
@property (nonatomic,copy)name nm_blk;
39. 用handler塊降低代碼分散程度

這條書上說的就是block的回調。只不過是把block放在方法中去使用。

//  Person.h
#import <Foundation/Foundation.h>
typedef void(^Blk)(NSString *name,int age);
@interface Person : NSObject
-(void)handler:(Blk)blk;
@end

//  Person.m
#import "Person.h
@implementation Person
-(void)handler:(Blk)blk{
    if(blk){
        blk(@"zhangsan" ,28);
    }
}
@end

//  使用
Person *per =[Person new];
[per handler:^(NSString *name, int age) {
     NSLog(@"%@ %d",name, age);
}];

這樣使用的好處是 在兩個對象通信的時候可以不使用delegate,方便了代碼的管理。其實這樣的用法很常見,多用于封裝網絡請求的基類。

40. 用塊引用其所屬對象時不要出現保留環

這個沒啥可說的

41. 多用派發隊列,少用同步鎖

派發隊列可用來表述同步語義,這種做法比使用@synchronize塊或NSLock對象更簡單
將同步與異步派發結合起來,可以實現與普通枷鎖機制一樣的同步行為,而這么做卻不會阻塞執行異步派發的線程
使用同步隊列及柵欄塊,可以令同步行為更加高效(不常用)

42. 多用GCD,少用performSelector系列方法

這個沒啥可說的

43. 掌握GCD及操作隊列的適用時機

這個沒啥可說的
解決多線程與任務管理問題時,派發隊列并非唯一方案
操作隊列提供了一套高層的Objective-C API 能實現純GCD所具備的絕大部分功能,而且還完成一些更為復雜的操作,那些操作弱改用GCD來實現,則需另外編寫代碼。
使用NSOperation對線程管理

44. 通過Dispatch Group機制,根據系統資源狀況來執行任務

這個沒啥可說的
一系列任務可歸入一個dispatch group之中。開發者可以在這組任務執行完畢時獲得通知
通過dispatch group,可以在并發式派發隊列里同時執行多項任務。此時GCD會根據系統西苑狀況來調度這些并發執行的任務。開發者若自己來實現此功能。則需要便攜大量代碼。

45. 使用dispatch_once來執行秩序運行一次的線程安全代碼
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
        <#code to be executed once#>
});
46.不用使用dispatch_get_current_queue

這個沒啥可說的
iOS系統6.0版本起,已經正式啟用此函數了

__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6,__MAC_10_9,__IPHONE_4_0,__IPHONE_6_0)
DISPATCH_EXPORT DISPATCH_PURE DISPATCH_WARN_RESULT DISPATCH_NOTHROW
dispatch_queue_t
dispatch_get_current_queue(void);


47.熟悉系統框架

打開Xcode command + shift + 0 選擇性的了解一些 Foundation、UIKit
也可以看看這篇博客 http://www.lxweimin.com/p/58bc11c800e4

48. 多用枚舉,少用for循環

因為枚舉遍歷的時候用的多線程(GCD并發執行),所以效率更快些。我覺得其實用什么都行。

NSArray *arr = @[@"b",@"c",@"s"];
[arr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
 }];
49. 對自定義其內存管理語義的collection使用無縫橋接
NSArray *anNSArray = @[@1,@3,@5,@8];
CFArrayRef acFArray =  (__bridge CFArrayRef)anNSArray;
NSLog(@"%@",acFArray);

通過無縫橋接技術,可以在Foundation框架中Objective-C對象與CoreFoundation框架中的C語言數據結構之間來回轉換。
在CoreFoundation層面穿件collection時,可以指定許多回調函數,這些函數表示此collection應如何處理其元素,然后可運用無縫橋接技術,將其轉換成具備特殊內存管理語義的Objective-C collection。

50. 構建緩存時選用NSCache而非NSDictionary

NSCache勝過NSDictionary之處在于,當系統資源耗盡時,它能自動刪減緩存。

51. 精簡Initialize與load的實現代碼

類初始化的時候一定會調用兩個方法

+(void)load{}

+ (void)initialize
{
    if (self == [<#ClassName#> class]) {
        <#statements#>
    }
}
  • load方法只會調用一次,不管該類的頭文件有沒有被使用,該類都會被系統自動調用,而且只調用一次。 當然了,如果不重寫這個方法的話,我們是不知道這個方法有沒有被調用的。
    如果分類也重寫了load方法,先調用類里的,在調用分類。

  • initialize 和load類似,不過在類被初始化的時候才會被調用(init之前)。需要注意的是,<#ClassName#>如果有子類繼承的時候要判斷類名。

52. 別忘了NSTimer會保留其目標對象
//  Person.h
#import <Foundation/Foundation.h>

@interface Person : NSObject
@property (nonatomic,strong)NSTimer *timer;
-(void)start;
-(void)stop;
@end

//  Person.m
#import "Person.h"
@implementation Person

-(void)start{
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(run) userInfo:nil repeats:YES];
}

-(void)run{
    NSLog(@"%s",__func__);
}

-(void)dealloc{
    NSLog(@"%s",__func__);
}

-(void)stop{
    [self.timer invalidate];
}
@end


調用
@property (nonatomic,strong)Person *person;

self.person = [Person new];
[self.person start];


-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self.person stop];
}

好,那么問題來了,是不是沒有調用dealloc方法,沒有調用dealloc方法就說明Person對象并沒有被銷毀,為什么沒有被銷毀

因為在控制器強引用了self.person,[self.person start]強引用了 self.timer; self.timer 的target指向了self(self.person)所以循環引用了。


怎么解決。 NSTimer銷毀的時候,把Person對象為nil即可

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

推薦閱讀更多精彩內容