[譯]iOS Core Foundation Design Concepts

本文翻譯: Core Foundation design concept

簡介

Core Foundation 是一組慨念源自OC基礎框架的編程接口,并使用c語言實現的庫.為了實現這個庫,Core Foundation用C語言實現一個限制對象模型.Core Foundation定義不透明類型來封裝數據和函數,之后就稱他們為"對象".
Core Foundation對象設計的編程接口具有易用性和可復用性.在普通層次下,Core Foundation有以下特性:

  • 能夠在繁雜多樣的框架和庫中共享數據和代碼
  • 使得在一定程度上獨立于操作系統成為可能
  • 支持使用unicode字符串的國際化
  • 提供一些API和其他有用的功能,包括一個插件架構,XML屬性列表等

Core Foundation使OS X上不同的框架和庫共享代碼與數據成為可能.應用,庫,框架讓你在平常C編程中,定義混合Core Foundation類型的接口;因此,它們可以計算數據--就像Core Foundation對象--通過這些接口設計算各自的數據.
Core Foundation在已確定的服務和Cocoa的Foundation框架之間提供"toll-free bridging"(無代價橋接). toll-free bridging能將函數參數中的Core Foundation對象替換成Cocoa對象或者反過來.
一些Core Foundation類型和函數是在不同操作系統上特定代碼實現的抽象. 使用這些API能更容易適配不同平臺.
date與number類型抽象了時間工具,并提供絕對時間和公歷時間的之間的轉換工具.它還抽象了數字值,并為這些內部表示不同的值提供的互轉工具.
Core Foundation給應用開發帶來其中一個主要的好處是支持國際化.通過框架中的字符串對象,Core Foundation使國際化在OS X與Cocoa上接口的編寫與實現變得更簡單,健壯和一致.這個特性的本質部分是一種類型--CFString, 代表一個16bit的Unicode字符數組. CFString對象能靈活地支持百萬字節的字符, 且使用一些足夠簡單的低層的接口就能計算字符數據.它達到了跟與之關聯的標準C字符串差不多的性能.
你應該閱讀這個文檔來了解Core Foundation之下的基本設計原則和Core Foundation對象跟Cocoa(Touch)對象之間的交互.

不透明類型

Core Foundation對象模型基于不透明類型,且支持封裝和多態函數.
基于不透明類型的對象的各個字段隱藏于客戶端,但是這些類型的函數能提供大多數字段值.Figure 1 描繪了不透明類型所隱藏的數據且僅展示其接口給客戶端.

Note: "Class"不是用來指向不透明類型的,盡管類和不透明類型概念上相似,可很多人可能被這個詞混淆.然而,Core Foundation文檔所指的類型是特定的,這些類型的數據承載實例就稱之為"對象"

Core Foundation有很多不透明類型,而且它們的名字說明了它們的預期用途.例如,CFString 是一個用來"展示"和操作Unicode字符數組的不透明類型(CF是Code Foundation的前綴). CFArray是基于下標的泛型集合.一個不透明類型支持的函數,常量和其他次要的數據類型通常定義在其類型對應名字的頭文件中.例如CFArray.h,CFArray包含定義符號.

Figure 1  An opaque type
Figure 1 An opaque type

不透明類型的優點

部分情況下,一個不透明類型似乎要通過令人沮喪的結構內容直接存取來增加一些沒有必要的限制. 此外,似乎不透明的類型可能會影響項目性能相關的開銷.但是不透明類型的好處要大于這些表面的局限性.
不透明類型為底層功能的實現提供更好的靈活性和抽象性.通過隱藏結構字段的詳細信息,Core Foundation減少發在客戶端(Xcode)編碼時,字段詳情被更改后代碼出錯的幾率.此外,如果暴露不透明類型并允許優化,可能會造成困惑(譯注: 其他人可能看不懂其優化代碼,還不如封裝起來).例如CFString "正式"代表UniChar的16bit字符數組.然而, CFString可能選擇儲存一個ASCII范圍內8bit數值的字符串.復制一個不可變的對象可能(經常發生)導致共同引用一個對象而不是內存中兩個獨立的對象.(查看Core Foundation內存管理編程指南).
繼續CFString這個例子,使用一個不透明類型來儲存字符似乎太笨重.事實證明,并不是這樣的,CPU消耗的資源比使用簡單的C字符數組高不了多少,況且經常比他們低.另外,不透明并不一定說明這一個不透明類型從不提供直接訪問內容的機制.CFString,對于它的實例,提供了CFStringGetCStringPtr函數來直接訪問.
最后,你可以在一定的程度上自定義一些不透明類型.例如,集合類型允許為集合的每一個成員上為喚醒函數定義一個回調.集合類型允許調用函數時定義一個回調(譯注:callback,可以理解為函數指針),并讓每個集合成員調用.

對象引用

你可以通過引用來指向一個Core Foundation對象(不透明類型).對于頭文件的中的每一個不透明類型,你將會注意到一行或兩行相似的,類似下面的語句:

typedef const struct __CFArray * CFArrayRef;
typedef struct __CFArray * CFMutableArrayRef;

聲明這些指針指向(私有的)不可變和可變版本的結構.Core Foundation中許多函數的參數和返回值采用對象引用類型,而且從不使用typedef私有結構的類型. 例如:

CFStringRef CFStringCreateByCombiningStrings(CFAllocatorRef alloc, CFArrayRef array, CFStringRef separatorString);

查看 對象的種類獲取更多信息,可變的的還有其他種類的不透明對象.
每一個Core Foundation不透明類型給他們的對象定義一個唯一類型ID,如在CFArray對象上的CFArrayRef.類型ID是類型為CFTypeID的整型,這個ID標識了一個Core Foundation所屬的不透明類型.在各種上下文中使用類型ID, 如在你操作各式各樣的容器時使用.Core Foundation提供一些編程性接口,用于獲取和計算類型ID的值.

重要:由于類型ID的值可以隨著版本的變化而變化,你的類型ID應該不能依賴已保存的或寫死的類型ID,也不應該被任何能觀察到的屬性賦值(例如賦給它一個簡單的整形:23333).

另外,Core Foundation定義了一個通用的對象引用(object-reference)類型, CFTypeRef,類似其他面向對象語言的基(root)類.這個通用的引用作為一個多態函數的參數與返回值的占位符類型,可以指向任何Core Foundation對象.查看多態函數獲取更多關于這個課題的信息.查看Core Foundation的內存管理指南討論使用對象引用時內存管理的相關問題.

多態函數

Core Foundation提供一些多態函數,這些函數可以將任意Core Foundation對象作為參數和(有一個例子:CFRetain)可以返回任意Core Foundation對象.這些參數和返回值的類型是CFTypeRef,是一個通用的對象引用(object-reference)類型.CFType是類似于其他面向對象語言中的根類,因為它的函數可以被其他所有對象復用.
你可以使用多態函數對所有的Core Foundation對象進行一些通用操作:

  • 引用計數
    CFType提供幾個多態函數來計算和獲取對象的引用計數.查看Core Foundation的內存管理指南獲取更多的關于這些函數的信息.
  • 比較對象
    CFEqual函數能比較任何兩個Core Foundation對象(查看比較對象).等式成立的基本條件取決于同類型對象的比較.例如,如果比較兩個CFString對象,該測試涉及逐個字符的比較.
  • 哈希對象
    CFHash函數返回一個唯一的能夠標識Core Foundation對象的哈希碼(查看比較對象).你可以把哈希碼當哈希表數據結構中的表地址.如果兩個對象相等(由CFEqual函數決定),他們必須有相同的哈希值.
  • 核查對象
    CFType提供核查對象的函數,從而了解它們的內容以及他們"所屬"的類型.CFCopyDescription函數返回一個描述該對象的字符串(更切確地說,是一個CFString對象的引用).CFCopyTypeIDDescription函數需要提供一個CFTypeID參數而不是CFTypeRef.這個函數返回一個描述標識一個不透明類型的類型ID的字符串引用.這些函數主要用來協助調試.查看核查對象獲取更多相關的函數.
    你還可以通過CFGetTypeID函數獲得不透明對象的類型ID,通過這個ID決定一個通用類型對象所屬的不透明類型,再將已知類型ID對應的值相比較.查看檢查對象獲取更多關于這個任務的信息.

對象的種類

不透明類型擁有多達3種基本種類,或者"口味".(譯注:這里為了跟之前的對象類型(object type)區分,故意使用種類或'口味').基于可擴展性和可編輯性的特點分為以下:

  • 不可變和固定大小
  • 可變和固定大小
  • 可變和不固定大小

可變對象是可編輯的,意味著他們的內容可以修改.不可變對象不能編輯的;一旦創建之后就無法再改變.對不可變對象的任何修改都會導致一些(譯注:編譯器)錯誤.一個固定大小的可變對象有一個最大值來限制其大小的增長;就CFString來說,一個CFString可能是字符串中的字符個數,對于一個容器來說,其限制可能是元素的數量.
一些不透明類型,例如CFStringCFArray,可以創建所有三種口味的對象.大部分不透明類型可以創建不可變的,固定大小的對象,至少有一個無限制的創建函數來創建無限制對象(如CFArrayCreate).決定可變對象的可變大小或不可變大小的是CreateMutable函數的容量(capacity)參數和長度最大值(maximum-length)參數;任何正整數都能生成對固定大小的對象,但是參數為0則生成一個可變大小對象.
使用帶有"Mutable"名字的類型指向可變對象,例如,CFMutableStringRef.

命名約定

Core Foundation中主要編程接口的約定是使用不透明類型的名字中最密切相關的符號作為符號的前綴.對于函數,這個前綴不僅標識這該函數"屬于"那個類型,而且經常用來標識函數動作(action)的目標(target)對象的類型(type).(有一個例外是那些以k作為前綴的常量).在頭文件中有一些例子:

/* from CFDictionary.h */
CF_EXPORT CFIndex CFDictionaryGetCountOfKey(CFDictionaryRef dict, const void *key);
/* from CFString.h */
typedef UInt32 CFStringEncoding;
/* from CFCharacterSet.h */
typedef enum {
  kCFCharacterSetControl = 1,
  kCFCharacterSetWhitespace,
  kCFCharacterSetWhitespaceAndNewline,
  kCFCharacterSetDecimalDigit,
  kCFCharacterSetLetter,
  kCFCharacterSetLowercaseLetter,
  kCFCharacterSetUppercaseLetter,
  kCFCharacterSetNonBase,
  kCFCharacterSetDecomposable,
  kCFCharacterSetAlphaNumeric,
  kCFCharacterSetPunctuation,
  kCFCharacterSetIllegal
  } CFCharacterSetPredefinedSet;

除上述之外,Core Foundation中有一小部分編程接口約定是有關于不透明類型和內存管理的.

  • Get,Copy和Create之間有著很重大的區別,在于函數的返回值的命名.如果你使用Get函數,只是無法確定對象的生命周期.為了確保對象能夠持續存在,你可以持有(retain)它(使用CFRetain函數),或者在一些情況下,復制(copy)一份.如果你使用Copy或Create函數,你必須負責釋放對象(使用CFRelease函數).更多詳情請查看Core Foundation內存管理指南

  • 部分Core Foundation對象有它們自己的命名約定,并以此加強通用操作的一致性.例如,集合(collection)將下列動詞嵌入函數名,已表示集合中的元素的特定操作.

    • Add意味'如果存在就添加,如果存在就不做任何事'(針對某一個集合實例)
    • Replace意味'如果存在就替換,如果不存在就不做任何事'
    • Set意味'如果不存在就添加,如果存在就替換'
    • Remove意味'如果存在就刪除,如果不存在就不做任何事'
  • CFIndex類型用于下標(index),計數(count),長度(length),和大小(size),并作為函數的參數或者返回值.這個類型(整形)的值(當前是32位),可以隨著處理器地址大小的增長而增長.在指針大小不同的架構上,如果是64位處理器,CFIndex可能是64位,這取決于int的大小.在Core Foundation參數中使用相同類型CFIndex的變量進行交互,可以確保您的代碼有更高的源碼兼容性.

  • 一些Core Foundation頭文件似乎定義不透明類型,但實際上卻包含便利函數而不是關聯一些特定的類型.恰當的例子是CFPropertyList.h.CFPropertyList是下列屬性列表類型中任意一個類型的占位符類型:CFString,CFDate,CFBoolean,CFNumber,CFDate,CFArrayCFDictionary.

  • 除非特殊說明,否則所有傳遞引用參數并打算返回值都可以接受NULL.這表明調用者不需要關心函數的返回值.

其他類型

Core Foundation定義若干個數據類型,并在函數中使用.這些類型存在的目的是抽象原始值.這個原始值可能隨處理器地址空間改變而改變.例如CFIndex類型,應用于下標(index), 計數(count),長度(length),和大小(size)參數.CFOptionFlags類則用于位字段參數,CFHashCode類型包含從CFHash函數和已確定的哈希回調中返回的哈希結果.
其他基本類型用于傳入函數和函數返回的比較值與范圍值.CFRange是一個指定線性隊列的任意一部分的結構,從字符串中的數組到集合中的元素.對于比較函數,CFComparisonResult類型定義枚舉常量來代表適當的返回值(等于,小于,大于).部分Core Foundation函數傳入一個回調到比較函數中去;如果你需要自定義比較操作,函數必須符合CFComparatorFunction中指定的類型(譯注:函數的參數必須與(const void *val1, const void *val2, void *context)相同).

重要: 只要其值是整形值,那么其類型一定是Core Foundation類型,特別是CFIndexCFTypeID,可以隨著處理器尋址大小的增長而增長.在Core Foundation參數中使用相同類型CFIndex的變量進行交互,可以讓確保您的代碼有更高的源碼兼容性.

Core Foundation中體統的其他不透明類型在其他主題中討論.

比較對象

你可用CFEqual函數來比較兩個Core Foundation對象.如果兩個對象在本質上是相等的,函數將返回一個boolean類型的true值."本質上"相等取決于相同類型的對象的比較.當你比較兩個CFString對象,不管他們的編碼和是否可變,當他們逐個字符完全匹配時, Core Foundation則認為他們本質上相等.兩個CFArray對象比較,當它們有相同數量的元素和數組中每一個元素對象與對應數組中的元素本質上相等,這時會認為他們本質上相等.很明顯,比較對象必須是相同類型(不管可變或不可變)才會認為是相等的.
下面代碼片段給你展示了可能使用CFEqual函數比較一個常量與傳入參數是否相等.
Listing 1 比較Core Foundation對象

void stringTest(CFStringRef myString) {
  Boolean equal = CFEqual(myString, CFSTR(“Kalamazoo”));
  if (!equal) {
    printf(“They’re not equal!");
  }
  else {
    printf(“They’re equal!”):
  }
}

核查對象

Core Foundation對象的主要特征是它們都基于一個不透明(或私有)類型;可能因此難以直接核查對象的內部數據.然而,基礎服務提供了兩個函數來檢查Core Foundation對象.這些函數返回對象及對象類型的描述信息.
為了找出Core Foundation對象的內容,調用CFCopyDescription函數并傳進其對象.然后打印所引用的字符串對象所"包含"的字符序列.

Listing 1 使用CFCopyDescription

void describe255(CFTypeRef tested) {
  char buffer[256];
  CFIndex got;
  CFStringRef description = CFCopyDescription(tested);
  CFStringGetBytes(description,
    CFRangeMake(0, CFStringGetLength(description)),
    CFStringGetSystemEncoding(), '?', TRUE, buffer, 255, &got);
    buffer[got] = (char)0;
    fprintf(stdout, "%s", buffer);
    CFRelease(description);
  }

這個例子顯示了一種打印描述信息(description)的途徑.你不應該使用CFStringGetBytes,而是使用CFString函數來獲取真正的字符串.
為了確定一個"未知"對象的類型,用CFGetTypeID函數取得它的類型ID,將值與已知的類型ID進行比較,直到匹配.可以使用CFGetTypeID獲取一個對象的類型ID.每一個不透明類型還定義了一個CFTypeGetTypeID表格的函數(例如CFArrayGetTypeID);這個函數返回給定類型的類型ID.在此之前,你可以測試一下一個CFType對象是否是指定不透明類型的成員.

CFTypeID type = CFGetTypeID(anObject);
if (CFArrayGetTypeID() == type)
  printf(“anObject is an array.”);
else
  printf(“anObject is NOT an array.”);

為了打印Core Foundation對象的類型在調試狀態下的相關信息.使用CFGetTypeID函數來獲取這個類型ID,然后通過這個值傳入CFCopyTypeIDDescription函數:

/* aCFObject is any Core Foundation object */
CFStringRef descrip = CFCopyTypeIDDescription(CFGetTypeID(aCFObject));

注意: 字符串基礎功能中包含兩個函數:CFShowCFShowStr,都聲明在CFString.h頭文件中.在調試模式下,你可以調用它們打印Core Foundation的描述.

重要: CFCopyDescriptionCFCopyTypeIDDescription只在調試模式下使用.不要創建任何依賴它們的代碼,因為描述信息與他們的格式隨時改變.

無代價橋接類型

在Core Foundation框架與Foundation框架中有若干可相互轉換的數據類型.可相互裝換的數據類型也被稱為無代價橋接(toll-free bridged)數據類型.這意味著你可以使用相同的數據結構作為參數傳進Core Foundation調用的函數和作為一個Objective-C消息發送的接收器.例如,NSLocale(查看NSLocale Class Reference), 與之對應的Core Foundation的CFLocal(查看CFLocale)是可相互轉換的.
不是所有的數據類型都是無代價橋接的,甚至通過他們的名字可能猜得出他們是有代價橋接的.例如NSRunLoop轉換到CFRunLoop不是無代價橋接,NSBundle轉換至CFBundle不是無代價橋接.NSDateFormate轉換到CFDateFormatter也不是.table 1提供了一張提供的無條件橋接的表.

注意: 在你使用corefoundation的集合時,如果安裝(install)一個自定義回調(call back),包括NULL回調.從Objective-C訪問時,該自定義回調的內存管理的行為是沒有定義的.

強制類型轉換和對象生命期的語義(Casting and Object Lifetime Semantics)

通過無條件橋接,當你在一個方法中,看到有些參數,例如NSLocale *參數,可以傳進一個CFLocaleRef;在函數看到CFLocaleRef參數,你可以傳一個NSLocale實例.不過你必須為編譯器提供其他信息: 首先, 將一個類型強制轉換(cast)為其他類型;另外,你可能還要指示出對象的聲明期語義.
編譯器理解Objective-C方法返回的Core Foundation類型和遵循過去Cocoa命名約定(查看高級內存管理編程指南).例如,編譯器知道在iOS中,通過UIColor本身并沒有CGColor方法來返回一個CGColor. 你必須使用適當的強制類型轉換(cast),就像下面所展示的:

NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]];
[colors addObject:(id)[[UIColor lightGrayColor] CGColor]];

編譯器不會自動管理Core Foundation對象的生命期.選擇強制類型轉換(cast)(在objc/runtime.h中定義)和Core Foundation風格的宏(在NSObject.h中定義)其中一個,告訴編譯器關于對象的持有者.

  • __bridge將一個指向Objective-C與Core Foundation兩者之一的指針相互轉換,沒有轉換持有權.

  • __bridge_retainedCFBridgingRetain強制類型轉換(cast)指向Objective-C的指針為Core Foundation指針并把持有權轉給你.
    你負責調用CFRelease或相關函數來放棄對象的持有權.

  • __bridge_transferCFBridgingRelease移動一個非Objective-C指針到Objective-C,并且將對象持有權交給ARC.
    ARC 有負責放棄對象的持有權.
    上述看起來就像下面這個例子:

    NSLocale *gbNSLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"];
    CFLocaleRef gbCFLocale = (__bridge CFLocaleRef)gbNSLocale;
    CFStringRef cfIdentifier = CFLocaleGetIdentifier(gbCFLocale);
    NSLog(@"cfIdentifier: %@", (__bridge NSString *)cfIdentifier);
    // Logs: "cfIdentifier: en_GB"
    
    CFLocaleRef myCFLocale = CFLocaleCopyCurrent();
    NSLocale *myNSLocale = (NSLocale *)CFBridgingRelease(myCFLocale);
    NSString *nsIdentifier = [myNSLocale localeIdentifier];
    CFShow((CFStringRef)[@"nsIdentifier: " stringByAppendingString:nsIdentifier]);
    

下一個例子展示Core Foundation內存管理函數的用法.這些函數由Core Foundation內存管理規則主宰:

- (void)drawRect:(CGRect)rect {

  CGContextRef ctx = UIGraphicsGetCurrentContext();
  CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
  CGFloat locations[2] = {0.0, 1.0};
  NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]];
  [colors addObject:(id)[[UIColor lightGrayColor] CGColor]];
  CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);
  CGColorSpaceRelease(colorSpace);  // Release owned Core Foundation object.

  CGPoint startPoint = CGPointMake(0.0, 0.0);
  CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds));
  CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint,
                              kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
                              CGGradientRelease(gradient);  // Release owned Core Foundation object.
}

無代價橋接類型

table 1 提供一個可在Core Foundation和Foundation之間相互裝換的數據類型的列表.對于每一對,表中來列舉了它們之間無代價橋接變得有效時OS X的版本.
Table 1 在Core Foundation和Foundation之間相互裝換的數據類型

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

推薦閱讀更多精彩內容

  • 版本記錄 前言 Core Foundation框架(CoreFoundation.framework)是一組C語言...
    刀客傳奇閱讀 2,774評論 0 3
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,199評論 30 471
  • 序言 目前形勢,參加到iOS隊伍的人是越來越多,甚至已經到供過于求了。今年,找過工作人可能會更深刻地體會到今年的就...
    iOS_Alex閱讀 1,629評論 1 24
  • 序言 目前形勢,參加到iOS隊伍的人是越來越多,甚至已經到供過于求了。今年,找過工作人可能會更深刻地體會到今年的就...
    麥兜兜買兜兜閱讀 684評論 1 4
  • 第1篇Objective-C準備篇 第1章Objective-C學習環境準備 1.1Objective-C基礎 1...
    YHWXQ簡簡單單的生活閱讀 1,045評論 2 2