iOS学习笔记29-系统服务(二)通讯录

一、通讯录

iOS中的通讯录是存储在数据库中的,由于iOS的权限设计,开发人员是不允许直接访问通讯录数据库的,实现通讯录操作需要使用到AddressBook.framework框架。

AddressBook.framework框架:
  • 可以从底层去操作通讯录的所有信息,做到精确控制
  • 是基于C语言编写的,无法使用ARC管理内存,需要开发者手动管理内存
  • 需要自构UI界面

iOS还提供了另外一个框架来供开发者操作通讯录,那就是AddressBookUI.framework

AddressBookUI.framework框架:
  • 该框架封装AddressBook.framework,向外提供现成视图控制器使用
  • 可以使用ARC管理内存
  • 高度封装化,界面固定,可定制性差

这两个框架各有各的优点,各有各的缺点,具体采用哪一种去操作通讯录看具体需求决定。

二、AddressBook

AddressBook.framework框架是基于C语言的,缺少面向对象的思想,所以我们可以把里面一些结构体理解为一个“类”

首先我们来了解几个核心结构体:
  1. ABAddressBookRef
    通讯录对象,全局管理通讯录操作,比如修改保存等
  1. ABRecordRef
    通用的记录对象,可以是一条联系人信息,也可以是一个群组,通过具体类型进行区分,每条记录都有一个唯一ID标识
  2. ABPersonRef
    联系人信息,不常用,可以用类型为kABPersonTypeABRecordRef代替。
  3. ABGroupRef
    群组信息,不常用,可以用类型为kABGroupTypeABRecordRef代替。
常使用到关于记录Record的C语言函数:
/* 获取一条记录对象的唯一标识ID */
ABRecordID ABRecordGetRecordID(ABRecordRef record);
/* 创建一条记录对象,类型为kABPersonType,表示一条联系人信息 */
ABRecordRef ABPersonCreate(void);
/* 创建一条记录对象,类型为kABGroupType,表示一条群组信息 */
ABRecordRef ABGroupCreate(void);
/* 获取指定属性的值 */
CFTypeRef ABRecordCopyValue(ABRecordRef record, ABPropertyID property);
/* 设置纪录的属性值,返回设置是否成功 */
bool ABRecordSetValue(
    ABRecordRef record, /* 记录 */
    ABPropertyID property, /* 属性 */
    CFTypeRef value, /* 值,可以是单值,也可以是多重值 */
    CFErrorRef* error /* 错误信息 */
);
/* 向多重值添加单值 */
bool ABMultiValueAddValueAndLabel(
    ABMutableMultiValueRef multiValue, /* 多重值 */
    CFTypeRef value, /* 单值 */
    CFStringRef label, /* 单值对应的属性名 */
    ABMultiValueIdentifier *outIdentifier /* 多重值的标示 */
);
/* 从多重值中取出指定索引的单值 */
CFTypeRef ABMultiValueCopyValueAtIndex(
    ABMultiValueRef multiValue, 
    CFIndex index
);
/* 删除指定的属性值 */
bool ABRecordRemoveValue(
    ABRecordRef record, /* 记录 */
    ABPropertyID property, /* 属性 */
    CFErrorRef* error /* 错误信息 */
);
常使用到的通讯录操作的函数
/* 创建通讯录对象 */
ABAddressBookRef ABAddressBookCreate(void);
/* 操作通讯录用户授权,注意无论成功与否回调都会调用 */
void ABAddressBookRequestAccessWithCompletion(
    ABAddressBookRef addressBook,  /* 通讯录 */
    ABAddressBookRequestAccessCompletionHandler completion /* 回调 */
);
/* 获取通讯录所有的记录 */
CFArrayRef ABAddressBookCopyArrayOfAllPeople(ABAddressBookRef addressBook);
/* 添加记录进通讯录 */
bool ABAddressBookAddRecord(
    ABAddressBookRef addressBook, /* 通讯录 */
    ABRecordRef record, /* 记录 */
    CFErrorRef* error /* 错误信息 */
);
/* 从通讯录删除记录 */
bool ABAddressBookRemoveRecord(
    ABAddressBookRef addressBook,/* 通讯录 */
    ABRecordRef record, /* 记录 */
    CFErrorRef* error/* 错误信息 */
);
/* 从通讯录中获取一个记录,根据记录ID */
ABRecordRef ABAddressBookGetPersonWithRecordID(
    ABAddressBookRef addressBook, /* 通讯录 */
    ABRecordID recordID /* 记录ID */
);
/* 保持通讯录,修改了通讯录需要保存提交修改 */
bool ABAddressBookSave(
    ABAddressBookRef addressBook, /* 通讯录 */
    CFErrorRef* error /* 错误信息 */
);
通讯录使用步骤:
  1. 创建通讯录对象ABAddressBookRef
  1. 请求用户授权操作通讯录ABAddressBookRequestAccessWithCompletion
  2. 查询所有通讯录的记录ABAddressBookCopyArrayOfAllPeople
  3. 添加记录,删除记录,修改记录
  4. 修改通讯录后,记住要通讯录保存ABAddressBookSave
下面是实际代码:
1. 创建通讯录并请求授权
/* 请求访问通讯录并获取通讯录所有记录 */
- (void)requestAddressBook{
    //创建通讯录对象
    self.addressBook = ABAddressBookCreate();
    
    //请求访问用户通讯录,注意无论成功与否block都会调用
    ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef error) {
        if (!granted) {
            NSLog(@"未获得通讯录访问权限!");
        }
        //获取所有通讯录记录
        [self initAllPerson];
        //刷新表格
        [self.tableView reloadData];
    });
}

/* 取得所有通讯录记录 */
- (void)initAllPerson{
    //取得通讯录访问授权
    ABAuthorizationStatus authorization = ABAddressBookGetAuthorizationStatus();
    //如果未获得授权
    if (authorization != kABAuthorizationStatusAuthorized) {
        NSLog(@"尚未获得通讯录访问授权!");
        return ;
    }
    //取得通讯录中所有人员记录
    CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(self.addressBook);
    self.allPerson = (__bridge NSMutableArray *)allPeople;
    //释放资源
    CFRelease(allPeople);
}
2. 添加联系人

/**
 *  添加一条记录
 *
 *  @param firstName  名
 *  @param lastName   姓
 *  @param iPhoneName iPhone手机号
 */
- (void)addPersonWithFirstName:(NSString *)firstName
                      lastName:(NSString *)lastName
                    workNumber:(NSString *)workNumber
{
    //创建一条记录
    ABRecordRef recordRef = ABPersonCreate();
    //添加名
    ABRecordSetValue(recordRef,kABPersonFirstNameProperty,(__bridge CFTypeRef)(firstName),NULL);
    //添加姓
    ABRecordSetValue(recordRef,kABPersonLastNameProperty,(__bridge CFTypeRef)(lastName),NULL);
    //创建一个多值属性,因为手机号可以有多个
    ABMutableMultiValueRef multiValueRef = ABMultiValueCreateMutable(kABStringPropertyType);
    //向多值属性中添加工作电话
    ABMultiValueAddValueAndLabel(multiValueRef,(__bridge CFStringRef)(workNumber),kABWorkLabel,NULL);
    //添加属性到指定记录,这里添加的是多值属性
    ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL);
    //添加记录到通讯录
    ABAddressBookAddRecord(self.addressBook, recordRef, NULL);
    //保存通讯录,提交更改
    ABAddressBookSave(self.addressBook, NULL);
    //释放资源
    CFRelease(recordRef);
    CFRelease(multiValueRef);
}
3. 删除联系人
/* 删除指定的记录 */
- (void)removePersonWithRecord:(ABRecordRef)recordRef{
    ABAddressBookRemoveRecord(self.addressBook, recordRef, NULL);//删除
    ABAddressBookSave(self.addressBook, NULL);//删除之后提交更改
}
/* 根据姓名删除记录 */
- (void)removePersonWithName:(NSString *)personName{
    CFStringRef personNameRef = (__bridge CFStringRef)(personName);
    //根据人员姓名查找
    CFArrayRef recordsRef = ABAddressBookCopyPeopleWithName(self.addressBook, personNameRef);
    CFIndex count = CFArrayGetCount(recordsRef);//取得记录数
    for (CFIndex i=0; i<count; ++i) {
        ABRecordRef recordRef = CFArrayGetValueAtIndex(recordsRef, i);//取得指定的记录
        ABAddressBookRemoveRecord(self.addressBook, recordRef, NULL);//删除
    }
    //删除之后提交更改
    ABAddressBookSave(self.addressBook, NULL);
    CFRelease(recordsRef);
}
4. 修改联系人
/**
 *  根据记录ID修改联系人信息
 *
 *  @param recordID   记录唯一ID
 *  @param firstName  姓
 *  @param lastName   名
 *  @param homeNumber 工作电话
 */
- (void)modifyPersonWithRecordID:(ABRecordID)recordID
                       firstName:(NSString *)firstName
                        lastName:(NSString *)lastName
                      workNumber:(NSString *)workNumber
{
    //根据记录ID获取一条记录
    ABRecordRef recordRef = ABAddressBookGetPersonWithRecordID(self.addressBook, recordID);
    //添加名
    ABRecordSetValue(recordRef,kABPersonFirstNameProperty,(__bridge CFTypeRef)(firstName),NULL);
    //添加姓
    ABRecordSetValue(recordRef,kABPersonLastNameProperty,(__bridge CFTypeRef)(lastName),NULL);
    //创建一个多值属性,因为手机号可以有多个
    ABMutableMultiValueRef multiValueRef = ABMultiValueCreateMutable(kABStringPropertyType);
    //向多值属性中添加工作电话
    ABMultiValueAddValueAndLabel(multiValueRef,(__bridge CFStringRef)(workNumber),kABWorkLabel,NULL);
    //添加属性到指定记录,这里添加的是多值属性
    ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL);
    //保存记录,提交更改
    ABAddressBookSave(self.addressBook, NULL);
    //释放资源
    CFRelease(multiValueRef);
}
5. UITableView显示
#pragma mark - TableView代理和数据源
- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section
{
    if (!self.allPerson) {
        return 0;
    }
    return self.allPerson.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *key = @"cellIdentify";
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:key];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
                                      reuseIdentifier:key];
    }
    //取得一条人员记录
    ABRecordRef recordRef = (__bridge ABRecordRef)self.allPerson[indexPath.row];
    //取得记录中得信息,注意这里进行了强转,不用自己释放资源
    NSString *firstName = (__bridge NSString *)ABRecordCopyValue(recordRef, kABPersonFirstNameProperty);
    NSString *lastName = (__bridge NSString *)ABRecordCopyValue(recordRef, kABPersonLastNameProperty);
    //获取手机号,注意手机号是ABMultiValueRef类,有可能有多条
    ABMultiValueRef phoneNumbersRef = ABRecordCopyValue(recordRef, kABPersonPhoneProperty);
    long count = ABMultiValueGetCount(phoneNumbersRef);
    for(int i = 0;i < count;++i){
        NSString *phoneLabel = (__bridge NSString *)(ABMultiValueCopyLabelAtIndex(phoneNumbersRef, i));
        NSString *phoneNumber = (__bridge NSString *)(ABMultiValueCopyValueAtIndex(phoneNumbersRef, i));
        NSLog(@"%@:%@",phoneLabel,phoneNumber);
    }
    cell.textLabel.text = [NSString stringWithFormat:@"%@ %@",firstName,lastName];
    if (count > 0) {
        cell.detailTextLabel.text = (__bridge NSString *)(ABMultiValueCopyValueAtIndex(phoneNumbersRef, 0));
    }
    //使用cell的tag存储记录ID
    cell.tag = ABRecordGetRecordID(recordRef);
    //记录最后一个记录的ID
    if (indexPath.row == self.allPerson.count - 1) {
        self.lastID = ABRecordGetRecordID(recordRef);
    }
    return cell;
}

6. UI点击以及视图控制器初始化和销毁
- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    //请求访问通讯录并获取通讯录所有记录
    [self requestAddressBook];
}
//由于在整个视图控制器周期内addressBook都驻留在内存中,所以当控制器视图销毁时销毁该对象
- (void)dealloc{
    if (self.addressBook != NULL) {
        CFRelease(self.addressBook);
    }
}
#pragma mark - UI点击
- (IBAction)addPerson:(id)sender {
    //添加联系人
    [self addPersonWithFirstName:@"liu"
                        lastName:@"ting"
                      workNumber:@"13412321332"];
    //获取所有通讯录记录
    [self initAllPerson];
    //刷新表格
    [self.tableView reloadData];
}
- (IBAction)removePerson:(id)sender {
    //删除联系人
    [self removePersonWithName:@"liu ting"];
    //获取所有通讯录记录
    [self initAllPerson];
    //刷新表格
    [self.tableView reloadData];
}
- (IBAction)changePerson:(id)sender {
    [self modifyPersonWithRecordID:self.lastID
                         firstName:@"XXXX"
                          lastName:@"YYY"
                        workNumber:@"1111111111"];
    //获取所有通讯录记录
    [self initAllPerson];
    //刷新表格
    [self.tableView reloadData];
}

三、AddressBookUI

AddressBookUI这个框架就提供了现成的控制器视图供开发者使用,高度封装化。

下面是这个框架中提供的控制器视图:
  1. ABPersonViewController
    用于查看联系人信息(可设置编辑)。
    需要设置displayedPerson属性来设置要显示或编辑的联系人。
  1. ABNewPersonViewController
    用于新增联系人信息。
  2. ABUnknownPersonViewController
    用于显示一个未知联系人(尚未保存的联系人)信息。
    需要设置displayedPerson属性来设置要显示的未知联系人。
  3. ABPeoplePickerNavigationController
    用于选择联系人。

前面三个控制器视图均继承于UIViewController,在使用过程中必须使用一个UINavigationController进行包装,否则只能看到视图内容无法进行操作,并且必须处理控制器的关闭操作,可以通过代理方法获得新增、修改的联系人。
最后一个控制器视图继承于UINavigationController,视图自身的“组”、“取消”按钮操作不需要开发者来完成,例如开发者不用在点击取消时关闭当前控制器视图,它自身已经实现了关闭方法。

下面是这四个控制器的代理方法:
#pragma mark - ABPersonViewController代理方法
//选择一个人员属性后触发,返回值YES表示触发默认行为操作,否则执行代理中自定义的操作
- (BOOL)personViewController:(ABPersonViewController *)personViewController
        shouldPerformDefaultActionForPerson:(ABRecordRef)person
                    property:(ABPropertyID)property
                  identifier:(ABMultiValueIdentifier)identifier;
#pragma mark - ABNewPersonViewController代理方法
/* 
    完成新增(点击取消和完成按钮时调用),注意这里不用做实际的通讯录增加工作,
    此代理方法调用时已经完成新增,当保存成功的时候参数中得person会返回保存的记录,如果点击取消person为NULL
 */
- (void)newPersonViewController:(ABNewPersonViewController *)newPersonView
       didCompleteWithNewPerson:(ABRecordRef)person;
#pragma mark - ABUnknownPersonViewController代理方法
//保存未知联系人时触发
- (void)unknownPersonViewController:(ABUnknownPersonViewController *)unknownCardViewController
                 didResolveToPerson:(ABRecordRef)person;
#pragma mark - ABPeoplePickerNavigationController代理方法
//选择一个联系人后调用,注意这个代理方法实现后选择属性的方法将不会再调用
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
                         didSelectPerson:(ABRecordRef)person;
//选择属性之后调用,注意如果上面的代理方法实现后此方法不会被调用
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker 
                         didSelectPerson:(ABRecordRef)person 
                                property:(ABPropertyID)property 
                              identifier:(ABMultiValueIdentifier)identifier;
//点击取消按钮调用
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker;
下面是具体代码示例【我包装了一个全局导航控制器】:
#import "addressBookUIViewController.h"
#import <AddressBookUI/AddressBookUI.h>

@interface addressBookUIViewController ()  <ABNewPersonViewControllerDelegate,
                                            ABUnknownPersonViewControllerDelegate,
                                            ABPeoplePickerNavigationControllerDelegate,
                                            ABPersonViewControllerDelegate>

@end

@implementation addressBookUIViewController

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

#pragma mark - UI事件
//点击添加联系人
- (IBAction)addPersonClick:(UIButton *)sender {
    //创建添加联系人视图控制器
    ABNewPersonViewController *newPersonController = 
                  [[ABNewPersonViewController alloc] init];
    //设置代理
    newPersonController.newPersonViewDelegate = self;
    //注意必须有一层导航控制器才能使用,否则不会出现取消和完成按钮,无法进行保存等操作
    [self.navigationController pushViewController:newPersonController animated:YES];
}
//点击未知联系人
- (IBAction)unknownPersonClick:(UIButton *)sender {
    //创建未知联系人视图控制器
    ABUnknownPersonViewController *unknownPersonController = 
                  [[ABUnknownPersonViewController alloc] init];
    //设置未知人员
    ABRecordRef recordRef=ABPersonCreate();
    ABRecordSetValue(recordRef, kABPersonFirstNameProperty, @"Kenshin", NULL);
    ABRecordSetValue(recordRef, kABPersonLastNameProperty, @"Cui", NULL);
    ABMultiValueRef multiValueRef = ABMultiValueCreateMutable(kABStringPropertyType);
    ABMultiValueAddValueAndLabel(multiValueRef, @"18500138888", kABHomeLabel, NULL);
    ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL);
    unknownPersonController.displayedPerson = recordRef;
    //设置代理
    unknownPersonController.unknownPersonViewDelegate = self;
    //设置其他属性
    unknownPersonController.allowsActions = YES;//显示标准操作按钮
    unknownPersonController.allowsAddingToAddressBook = YES;//是否允许将联系人添加到地址簿
    //释放资源
    CFRelease(multiValueRef);
    CFRelease(recordRef);
    
    [self.navigationController pushViewController:unknownPersonController animated:YES];
}
//点击显示联系人
- (IBAction)showPersonClick:(UIButton *)sender {
    //创建显示联系人视图控制器
    ABPersonViewController *personController = [[ABPersonViewController alloc] init];
    //设置联系人,取得id为1的联系人记录
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
    ABRecordRef recordRef = ABAddressBookGetPersonWithRecordID(addressBook, 1);
    personController.displayedPerson = recordRef;
    //设置代理
    personController.personViewDelegate = self;
    //设置其他属性
    personController.allowsActions = YES;//是否显示发送信息、共享联系人等按钮
    personController.allowsEditing = YES;//允许编辑
    
    [self.navigationController pushViewController:personController animated:YES];
}
//点击选择联系人
- (IBAction)selectPersonClick:(UIButton *)sender {
    //创建选择联系人导航视图控制器
    ABPeoplePickerNavigationController *peoplePickerController =
                [[ABPeoplePickerNavigationController alloc] init];
    //设置代理
    peoplePickerController.peoplePickerDelegate = self;
    //以模态弹出
    [self presentViewController:peoplePickerController animated:YES completion:nil];
}

#pragma mark - ABNewPersonViewController代理方法
/* 
    完成新增(点击取消和完成按钮时调用),注意这里不用做实际的通讯录增加工作,
    此代理方法调用时已经完成新增,当保存成功的时候参数中得person会返回保存的记录,
    如果点击取消person为NULL
 */
- (void)newPersonViewController:(ABNewPersonViewController *)newPersonView
       didCompleteWithNewPerson:(ABRecordRef)person
{
    //如果有联系人信息
    if (person) {
        NSLog(@"%@ 信息保存成功.",(__bridge NSString *)(ABRecordCopyCompositeName(person)));
    }else{
        NSLog(@"点击了取消.");
    }
    //返回主视图窗口
    [self.navigationController popToRootViewControllerAnimated:YES];
    
}
#pragma mark - ABUnknownPersonViewController代理方法
//保存未知联系人时触发
- (void)unknownPersonViewController:(ABUnknownPersonViewController *)unknownCardViewController
                 didResolveToPerson:(ABRecordRef)person
{
    if (person) {
        NSLog(@"%@ 信息保存成功!",(__bridge NSString *)(ABRecordCopyCompositeName(person)));
    }
    //返回主视图窗口
    [self.navigationController popToRootViewControllerAnimated:YES];
}

#pragma mark - ABPersonViewController代理方法
//选择一个人员属性后触发,返回值YES表示触发默认行为操作,否则执行代理中自定义的操作
- (BOOL)personViewController:(ABPersonViewController *)personViewController
        shouldPerformDefaultActionForPerson:(ABRecordRef)person
                    property:(ABPropertyID)property
                  identifier:(ABMultiValueIdentifier)identifier
{
    if (person) {
        NSLog(@"选择了属性:%d",property);
        NSLog(@"值为:%@", (__bridge NSString *)ABRecordCopyValue(person, property));
    }
    return NO;
}
#pragma mark - ABPeoplePickerNavigationController代理方法
//选择一个联系人后调用,注意这个代理方法实现后选择属性的方法将不会再调用
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
                         didSelectPerson:(ABRecordRef)person
{
    if (person) {
        NSLog(@"选择了%@.",(__bridge NSString *)(ABRecordCopyCompositeName(person)));
    }
}
//点击取消按钮后调用
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{
    NSLog(@"取消选择.");
}
@end



代码Demo点这里:LearnDemo里面的AddressBookDemo

如果有什么问题可以在下方评论区留言,我会积极响应的!O(∩_∩)O哈!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 6转载-->>IOS框架和服务 在iOS中框架是一个目录,包含了共享资源库,用于访问该资源库中储存的代码的头文件,...
    李小六_阅读 3,597评论 2 24
  • 在iOS中框架是一个目录,包含了共享资源库,用于访问该资源库中储存的代码的头文件,以及图像、声音文件等其他资源。共...
    ch123阅读 1,755评论 0 1
  • 文/半颗橙子@半间书房 台湾女作家陈雪在深圳新书见面会上给书房君的签名赠字,好喜欢她写的这句话:“所有经历都不会白...
    半间书房阅读 1,454评论 1 7
  • 这一段写了学习的方法和有关知识的故事,人生有无数选择,而这本书,不是答案,但能帮助我们找到答案。
    文魁大脑俱乐部潘若琨阅读 174评论 0 0
  • 很多时候我就希望下班回家之后有一碗速成的热腾腾的面条,今天来介绍一个私人秘籍。 在周六日空余时间制作牛肉汤头,...
    追寻七色花阅读 219评论 0 0