菜鸟:IOS 学习:磨难记 (第五天)

分析开发者指南源码  GI地址
分析通讯录 模块contact 中model 文件

IAddressBook.h IIAddressBook.m


知识重点:
1、数组  
  不可变  
NSArray*array=[[NSArray alloc] init];  

  对应 

int i = {12,3};

  可变 

NSMutableArray *mutableArray =[[NSMutableArray alloc] init];  

  对应 

int a[10] = {1};


2、CLASS消息机制  参考文档Cocoa深入检出消息机制
1,首先去该类的方法 cache 中查找,如果找到了就返回它;

2,如果没有找到,就去该类的方法列表中查找。如果在该类的方法列表中找到了,则将 IMP 返回,并将它加入cache中缓存起来。根据最近使用原则,这个方法再次调用的可能性很大,缓存起来可以节省下次调用再次查找的开销。
3,如果在该类的方法列表中没找到对应的 IMP,在通过该类结构中的 super_class指针在其父类结构的方法列表中去查找,直到在某个父类的方法列表中找到对应的IMP,返回它,并加入cache中;

4,如果在自身以及所有父类的方法列表中都没有找到对应的 IMP,则看是不是可以进行动态方法决议;

5,如果动态方法决议没能解决问题,进入消息转发流程



二、分析源码知识重点


1


ABMultiValueCopyLabelAtIndex 得到手机的多项属性


ABAddressBookCopyLocalizedLabel 得到本地化版本的属性标签




2CFSTringref NSString


CoreFoundation里面的CFStringRefNSString*是可以直接转换的,两种也都有一个相似的用来直接赋常量的操作。例如:


CFStringRef a = CFSTR("a");


NSString *b = @"b";


CFSTR分配出来的字符串对象是不能自己释放的


一个autorelease的对象




3stringWithStringinitWithString


[NSString stringWithString:@""] stringWithString 是类方法,返回一个auto-released的指向NSString的指针,会自动释放,适合临时变量,在一个函数体内部使用


[[NSString alloc] initWithString:@""] initWithString 实例方法,返回一个指向NSString的指针,同时该对象的retain count1,需要手动释放


4stringByReplacingOccurrencesOfString


[s stringByReplacingOccurrencesOfString:@"s"withString:@"x"]; //S替换为X


5ABRecordCopyValue


(__bridgeNSDate *)ABRecordCopyValue(person, kABPersonModificationDateProperty); //最后一次修改該条记录的时间返回记录数据


6ABRecordCopyCompositeName 返回名称


7ABAddressBookGetPersonWithRecordID  返回某个人的记录


8ABMultiValueCopyValueAtIndex 返回指定位置的多值属性


9[array addObject:...] : 向可变数组尾部添加数据对象。

[array addObjectsFromArray:..] :向可变数组尾部添加一个数组对象。


10ABPersonHasImageData  //表示某人是否有图片


11ABPersonCopyImageData //返回某人图片


12


NSData  主要用于数据缓冲


[UIImage imageWithData:data]  创建图片数据


13ABPersonRemoveImageData 删除图片数据


14ABPersonSetImageData 设置新图片数据


15


stringWithFormat 格式化字符串


[NSString stringWithFormat@"%@", stringName]


16ABMultiValueAddValueAndLabel  //添加多项值到指定标示


17ABRecordSetValue   //添加记录


18CFDictionaryCreate  //创建一个不变的字典


IIAddressBook.h

#import <Foundation/Foundation.h>
#import <AddressBook/AddressBook.h>
//地址薄框架提供联系人数据库,通讯数据库等

@interface IIAddressBook : NSObject {
    
}

// get label of phone number (e.g. Mobile, Home, etc)
/**
  + 代表类方法
 **/
//得到手机数据 ABMultiValueRef 某一个可能有多个字段数值的记录
+ (NSString *)getPhoneLabel:(ABMultiValueRef)phones index:(int)index;

// get full name of contact 单个人个名称 ABAddressBookRef 某个通讯录
+ (NSString *)getFullName:(ABAddressBookRef)addressBook personId:(int)personId;

//某个人的名称 ABRecordRef  某一条通讯录记录
+ (NSString *)getFullName:(ABRecordRef)person;

// get all phone numbers of one contact 手机号码
//获取某联系人全部电话  ABRecordRef  某一条通讯录记录
+ (NSArray *)getPhones:(ABRecordRef)person;

// get all emails of one contact 邮箱
//获取某联系人全部邮箱 ABRecordRef  某一条通讯录记录
+ (NSArray *)getEmails:(ABRecordRef)person;

// get image of contact
//获取某联系人头像 ABRecordRef  某一条通讯录记录
+ (UIImage*)getImageByPerson:(ABRecordRef)person;

//获取某联系人小头像 ABRecordRef  某一条通讯录记录
+ (UIImage*)getSmallImage:(ABRecordRef)person size:(CGSize)size;

//设置某联系人名称 ABRecordRef  某一条通讯录记录
+ (NSString*)getShortName:(ABRecordRef)person;

/**
 * 类消息 返回最近修改的时间
 * ABRecordID 记录的ID int 类型
 **/
+ (NSDate*)copyModificationDate:(ABRecordRef)person;

// set address into contact
//设置某联系人地址 ABRecordID 记录的ID int 类型
+ (BOOL)addAddress:(ABRecordRef)person street:(NSString*)street;

// set phones into contact
//设置某联系人电话 ABRecordID 记录的ID int 类型
+ (BOOL)addPhone:(ABRecordRef)person phone:(NSString*)phone;

// set image into contact
//设置某联系人头像 ABRecordID 记录的ID int 类型
+ (BOOL)addImage:(ABRecordRef)person image:(UIImage*)image;

//判断某联系人邮箱数据 ABRecordID 记录的ID int 类型
+ (NSArray *)getEmailsWithAddressBook:(ABRecordID)personId addressBook:(ABAddressBookRef)addressBook;

//判断某联系人电话数据 ABRecordID 记录的ID int 类型
+ (NSArray *)getPhonesWithAddressBook:(ABRecordID)personId addressBook:(ABAddressBookRef)addressBook;

//判断某联系人是否有电话 ABRecordRef  某一条通讯录记录
+ (BOOL)hasPhones:(ABRecordRef)person;

//判断某联系人是否有邮箱 ABRecordRef  某一条通讯录记录
+ (BOOL)hasEmails:(ABRecordRef)person;

@end

IIAddressBook. m

#import "IIAddressBook.h"

@implementation IIAddressBook


/**
 *  得到手机数据
 *  1、获取手机lable数据
 *  2、转化NSString类型
 *  3、替换成正常数据,返回
 */
// return label, but remove prefix and suffix in "_$!<Mobile>!$_"
+ (NSString *)getPhoneLabel:(ABMultiValueRef)phones index:(int)index
{
    /**
     * CFStringRef 赋值常量
     *ABMultiValueCopyLabelAtIndex 得到手机的多项属性
     ABAddressBookCopyLocalizedLabel 得到本地化版本的属性标签
     */
    CFStringRef origLabel = ABMultiValueCopyLabelAtIndex(phones, index);

    CFStringRef localizedLabel = ABAddressBookCopyLocalizedLabel(origLabel);
    
    /**
     *改进版
     * CFStringRef localizedLabel = ABAddressBookCopyLocalizedLabel(CFAutoRelease(ABMultiValueCopyLabelAtIndex(phones, index)));;
     **/
    //转换为字符串
    NSString* finalLabel = [NSString stringWithString:(__bridge NSString *)localizedLabel];
    
    //替换
    finalLabel = [finalLabel stringByReplacingOccurrencesOfString:@"_$!<" withString:@""];
    finalLabel = [finalLabel stringByReplacingOccurrencesOfString:@">!$_" withString:@""];
    
    //返回处理完的手机数据
    return finalLabel;
}

/**
 * 返回 最近修改的时间
 **/
+ (NSDate*)copyModificationDate:(ABRecordRef)person
{
    //最后一次修改該条记录的时间
    NSDate* date = (__bridge NSDate *)ABRecordCopyValue(person, kABPersonModificationDateProperty);
    
    return date;
}

/**
 *  获取某联系人的名称
 *  1、获取某个人的记录
 *  2、如果存在数据,调用类消息getFullName处理
 */
+ (NSString *)getFullName:(ABAddressBookRef)addressBook personId:(int)personId
{
    //ABAddressBookGetPersonWithRecordID 返回某个人的记录
    ABRecordRef personRef = ABAddressBookGetPersonWithRecordID(addressBook, personId);
    //如果没有数据,跳出
    if (!personRef)
        return nil;
    else { //如果有数据,调用类消息处理
        return [IIAddressBook getFullName:personRef];
    }
}

/**
 *  获取某联系人名称
 *  1、从某个人的记录提取名称
 *  2、如果存在数据,转化字符串后返回
 */
+ (NSString *)getFullName:(ABRecordRef)person
{
    //ABRecordCopyCompositeName 返回名称
    CFStringRef name = ABRecordCopyCompositeName(person);
    if (name == NULL){ //如果名字为空,跳出
        return [NSString stringWithString:@""];
    }
    //转化微字符串
    NSString* ret = [NSString stringWithString:(__bridge NSString*)name];
    
    //释放内存
    CFRelease(name);
    
    //返回名称
    return ret;
}


/**
 *  获取某联系人全部电话
 *  1、取出某个人的记录
 *  2、如果存在数据,调用处理电话的类消息getPhones
 */
+ (NSArray *)getPhonesWithAddressBook:(ABRecordID)personId addressBook:(ABAddressBookRef)addressBook
{
     //ABAddressBookGetPersonWithRecordID 返回某个人的记录
    ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressBook, personId);
    if (person){ //有则调用处理电话消息
        return [IIAddressBook getPhones:person];
    }
    else { 
        return nil;
    }
}
/**
 *  判断某联系人是否有电话
 *  1、调用处理电话消息 getPhones
 *  2、存在数据,返回YES ,没有返回NO
 */
// get the first phone number to display
+ (BOOL)hasPhones:(ABRecordRef)person
{
    //调用处理电话消息
    NSArray* phones = [IIAddressBook getPhones:person];
    if (phones != nil && [phones count] > 0){ //返回BOOL
        return YES;
    }
    else {
        return NO;
    }
}

/**
 *  判断某联系人是否有邮箱
 *  1、调用处理邮箱消息 getEmails
 *  2、存在数据,返回YES ,没有返回NO
 */
+ (BOOL)hasEmails:(ABRecordRef)person
{
    NSArray* emails = [IIAddressBook getEmails:person];
    if (emails != nil && [emails count] > 0){
        return YES;
    }
    else {
        return NO;
    }
    
}
/**
 *  获取某联系人全部电话
 *  1、取出某个人的记录
 *  2、如果存在数据,循环把转化后字符串电话数据压入数组
 *  3、返回数据
 */
+ (NSArray *)getPhones:(ABRecordRef)person
{
    //可变数组初始化
    NSMutableArray* phoneList = [[NSMutableArray alloc] init];
    
    //读取电话多值
    ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);    
    if (phones){ //如果数据存在
        int count = ABMultiValueGetCount(phones); //返回电话总数
        for (CFIndex i = 0; i < count; i++) {
            //NSString *phoneLabel       = (__bridge NSString *)ABMultiValueCopyLabelAtIndex(phones, i);
            //转化为多个电话数据为字符串
            NSString *phoneNumber      = (__bridge NSString *)ABMultiValueCopyValueAtIndex(phones, i);
            
            //NSLog(@"phone label (%@), number (%@)", phoneLabel, phoneNumber);
            //电话数据压入数组 addObject 向可变数组尾部添加数据对象
            [phoneList addObject:phoneNumber];

        }
    }
    //释放内存,返回数据
    CFRelease(phones);
    return phoneList;
}

/**
 *  获取某联系人全部电话
 *  1、取出某个人的记录
 *  2、如果存在数据,循环把转化后字符串电话数据压入数组
 *  3、返回数据
 */
+ (NSArray *)getEmailsWithAddressBook:(ABRecordID)personId addressBook:(ABAddressBookRef)addressBook
{
    //返回某个人的记录
    ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressBook, personId);
    if (person){ //存在回调邮箱处理消息 getEmails
        return [IIAddressBook getEmails:person];
    }
    else { //没有数据跳出
        return nil;
    }
}

/**
 *  获取某联系人全部电话
 *  1、取出某个人的记录
 *  2、如果存在数据,循环把转化后字符串邮箱数据压入数组
 *  3、返回数据
 */
// can be refactored to the same implementation later
+ (NSArray *)getEmails:(ABRecordRef)person
{
    //可变数组
    NSMutableArray* emailList = [[NSMutableArray alloc] init];
    
    //读取邮箱多值
    ABMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);
    
    if (emails){ //如果有邮箱数据
        int emailCount = ABMultiValueGetCount(emails);
        for (CFIndex i = 0; i < emailCount; i++) {
            //转化为多个邮箱数据为字符串
            NSString *label       = (__bridge NSString *)ABMultiValueCopyLabelAtIndex(emails, i);
            NSString *value      = (__bridge NSString *)ABMultiValueCopyValueAtIndex(emails, i);
            
           // NSLog(@"email label (%@), number (%@)", label, value);
            
            [emailList addObject:value];

        }
    }
    //释放内存,返回数据
    CFRelease(emails);
    
    return emailList;
}

/**
 *  获取某联系人头像
 *  1、初始化图片类型
 *  2、判断是否有图片,如果有先读入换缓冲区,在转化微图片类型
 *  3、返回图片数据
 */
+ (UIImage*)getImageByPerson:(ABRecordRef)person
{
    UIImage* image = nil;//初始化图片类型
    
    if (ABPersonHasImageData(person)){ //表示一人是否有图片
        
        //返回图片到缓冲
        NSData* data = (__bridge NSData *)ABPersonCopyImageData(person);
        image = [UIImage imageWithData:data];//转化图片类型

    }
    
    return image;    
}

/**
 *  获取某联系人小头像
 *  1没完工
 */
+ (UIImage*)getSmallImage:(ABRecordRef)person size:(CGSize)size
{
    UIImage* image = [IIAddressBook getImageByPerson:person];
    
    if (image != nil){
        // resize image
        //return [image imageByScalingAndCroppingForSize:size];
    }
    
    return nil;
}


/**
 *  设置某联系人名称
 *  1、读取名,和姓
 *  2、设置姓名完整标示,姓,名完整行处理
 *  3、根据标示,组合姓名
 */
+ (NSString*)getShortName:(ABRecordRef)person
{
    //返回名
    NSString* firstName = (__bridge NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
    //返回姓
    NSString* lastName  = (__bridge NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
    //返回公司
    NSString* orgName = (__bridge NSString *)ABRecordCopyValue(person, kABPersonOrganizationProperty);
    
    BOOL useOrgName = NO; //姓名是否完整标示
    
    if (firstName == nil && lastName == nil) //如果姓名都有,设置YES
        useOrgName = YES;
    
    if (firstName == nil) // 处理名
        firstName = @"";
    
    if (lastName == nil) //处理姓
        lastName = @"";        
    
    NSString* fullName; //姓名
    
    if (useOrgName == NO){ //如果姓名完整
        NSString* countryCode; //是否多国判断
        //NSString* countryCode = [LocaleUtils getCountryCode];
        if (countryCode != nil && ( [countryCode isEqualToString:@"CN"] == YES ||
                                   [countryCode isEqualToString:@"TW"] == YES ||
                                   [countryCode isEqualToString:@"KR"] == YES ||
                                   [countryCode isEqualToString:@"JP"] == YES)                                  
            )
        { 
            if ([lastName length] > 0){  //如果姓,名有数据,则把姓,名设置给全名变量
                fullName = [NSString stringWithFormat:@"%@ %@", lastName, firstName];    
            }
            else { //否则把名设置给全名变量
                fullName = [NSString stringWithString:firstName];
            }
            
        }//默认不区分国际
        else {            
            if ([firstName length] > 0){ //如果名有数据,则把名设置给全名变量
                fullName = [NSString stringWithFormat:@"%@", firstName];    
            }
            else { //否则把姓设置给全名变量
                fullName = [NSString stringWithString:lastName];
            }
            
        }    
    } //如果姓名不完整
    else {
        
        if (orgName == nil) //标示为空
            orgName = @"";
        //格式化标示
        fullName = [NSString stringWithFormat:@"%@", orgName];
    }
    
    //返回姓名
    return fullName;
    
}

/**
 *  设置电话
 *  1、初始化一些参数
 *  2、添加多项值到指定标示
 *  3、添加多条记录
 */
+ (BOOL)addPhone:(ABRecordRef)person phone:(NSString*)phone
{
    //创建一个新的,空的,可变的多值属性
    ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABMultiStringPropertyType);
    
    CFErrorRef anError = NULL;
    
    // The multivalue identifier of the new value isn't used in this example,
    // multivalueIdentifier is just for illustration purposes.  Real-world
    // code can use this identifier to do additional work with this value.
    ABMultiValueIdentifier multivalueIdentifier;//多项标示符
    
    //添加多项值到指定标示
    if (!ABMultiValueAddValueAndLabel(multi, (__bridge CFStringRef)phone, kABPersonPhoneMainLabel, &multivalueIdentifier)){
        CFRelease(multi);
        return NO;
    }
    
    //添加记录
    if (!ABRecordSetValue(person, kABPersonPhoneProperty, multi, &anError)){
        CFRelease(multi);
        return NO;
    }
    //释放内存,返回BOOL
    CFRelease(multi);
    return YES;
}


/**
 *  设置地址
 *  1、初始化一些参数
 *  2、添加多项值到指定标示
 *  3、添加多条记录
 */
+ (BOOL)addAddress:(ABRecordRef)person street:(NSString*)street
{
    //创建一个新的,空的,可变的多值属性
    ABMutableMultiValueRef address = ABMultiValueCreateMutable(kABDictionaryPropertyType);
    
    static int  homeLableValueCount = 5;
    
    // Set up keys and values for the dictionary.
    CFStringRef keys[homeLableValueCount];//键数组
    CFStringRef values[homeLableValueCount];//值数组
    keys[0]      = kABPersonAddressStreetKey; //街道
    keys[1]      = kABPersonAddressCityKey; //城市标示
    keys[2]      = kABPersonAddressStateKey;//州
    keys[3]      = kABPersonAddressZIPKey; //邮编
    keys[4]      = kABPersonAddressCountryKey; //国家
    values[0]    = (__bridge CFStringRef)street;
    values[1]    = CFSTR("");
    values[2]    = CFSTR("");
    values[3]    = CFSTR("");
    values[4]    = CFSTR("");
    
    //CFDictionaryCreate 创建一个不变的字典 
    CFDictionaryRef aDict = CFDictionaryCreate(
                                               kCFAllocatorDefault,
                                               (void *)keys,
                                               (void *)values,
                                               homeLableValueCount,
                                               &kCFCopyStringDictionaryKeyCallBacks,
                                               &kCFTypeDictionaryValueCallBacks
                                               );
    
    // Add the street address to the person record.
    ABMultiValueIdentifier identifier; //标示
    
    //添加多项值到指定标示
    BOOL result = ABMultiValueAddValueAndLabel(address, aDict, kABHomeLabel, &identifier);
    CFErrorRef error = NULL;
    //添加记录
    result = ABRecordSetValue(person, kABPersonAddressProperty, address, &error);
    
    //释放内存,返回数据
    CFRelease(aDict);    
    CFRelease(address);    
    
    return result;
}

/**
 *  设置某联系人头像
 *  1、删除旧图片
 *  2、设置新的图片,返回图片数据
 */
+ (BOOL)addImage:(ABRecordRef)person image:(UIImage*)image
{
    CFErrorRef error = NULL; //错误类型记录
    
    // remove old image data firstly
    ABPersonRemoveImageData(person, NULL); //删除旧的图片数据
    
    // add new image data 设置新图片数据
    BOOL result = ABPersonSetImageData (
                                        person,
                                        (__bridge CFDataRef)UIImagePNGRepresentation(image),
                                        &error
                                        );    
    
    //    CFRelease(error);
    
    return result;
}

@end



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值