类的静态方法去作为自己的工具类(系统工具交互的功能需求)

   在项目开发中,经常避免一些与系统工具交互的功能需求。比如说开启蓝牙,开启相机,通讯录功能,还有数据加密等等。
   由于这些功能的实现没有实例化的必要,并且又是许多项目都共用的功能,所以一般我们会作为类的静态方法去作为自己的工具类。
 
  以下是一段将字典的键值对导入通讯录的静态方法代码。
  假如说现在有一个这样的逻辑流程,C层按钮交互,将页面某个数据加密导入通讯录。
  让我们以MVC的思维梳理一下整过流程。
  在这整个事件中,有三个参与者。页面(C层),加密(M层),通讯录导入(M层)。
  为了简写,我们把页面(C)定义为A,加密(M层)定义为B,通讯录导入(M层)定义为C。
  结果也有三种,第一种是导入失败,第二种是能够导入成功但是通讯录中已经存在该联系人(需要提示A【用户】该次导入是否要覆盖掉已经存在的联系人),第三种是能够导入成功并且通讯录中没有该联系人。
  方案也有三种,第一种是A将加密导入通讯录指令告知B,B执行加密命令后再将数据传递给C,C进行通讯录导入将结果告知B,B再告知C。 实现上为了简洁可以将该逻辑代码封装为B的一个方法,B调用C的静态方法将返回参数通过自己的方法告知A,B和C的两个方法返回参数为int类型123分 别表示三种情况。
  第二种方案跟第一种方案类似,主要是由于int类型的表述结果不够直观,可以通过回调代理去执行,如-(void)setAddressSuccess    -(void)setAddresFaild   -(void)setAddresExist  代理方式更为直观,便于开发人员自身检测以及维护人员维护。
  第三种方案是A将处理三种结果的代码块作为Block参数送给B,B执行完加密之后将A交于自己的Block送给C,C在执行完导入操作之后直接执行Block,不需要将自己的结果告知任何人。

   以下代码是第二种方案和第三种方案融合处理,主要为了便于看到各种方案的利与弊。
   首先是C的静态方法

+ (BOOL)SetAddressBookWithInfo:(NSMutableDictionary *)info RePetBlock:(void (^)(void))block
{
    //获取通讯录信息
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(nil, nil);
    // ABRecordRef是一个属性的集合,相当于通讯录中联系人的对象
    ABRecordRef person = ABPersonCreate();
    //写入名字
    NSString *firstName = [info objectForKey:@"firstName"];
    // 保存到联系人对象中,每个属性都对应一个宏,例如:kABPersonFirstNameProperty
        // 设置firstName属性
        ABRecordSetValue(person, kABPersonFirstNameProperty, (__bridge CFTypeRef) firstName, NULL);
    //写入图片
    if(![[info objectForKey:@"image"] isKindOfClass:[NSNull class]])
    {
        UIImage *image = [UIImage imageNamed:@"icon80-80.png"];
        NSData *data = UIImageJPEGRepresentation(image, 1.0);
        ABPersonSetImageData(person, (__bridge CFDataRef) data, NULL);
    }
    //写入公司
    if([info objectForKey:@"company"])
    {
        ABRecordSetValue(person, kABPersonOrganizationProperty, (__bridge CFTypeRef) [info objectForKey:@"company"], NULL);
    }
    //写入公司地址
    if([info objectForKey:@"companyAddress"])
    {
        ABMutableMultiValueRef multiAddress = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);
        NSMutableDictionary *addressDictionary = [[NSMutableDictionary alloc] init];
        [addressDictionary setObject:[info objectForKey:@"companyAddress"] forKey:(NSString *) kABPersonAddressStreetKey];
        ABMultiValueAddValueAndLabel(multiAddress, (__bridge CFTypeRef)(addressDictionary), kABWorkLabel, NULL);
        
        //设置address
        ABRecordSetValue(person, kABPersonAddressProperty, multiAddress, nil);
    }
    //写入电话
    NSMutableArray *phones = [NSMutableArray arrayWithCapacity:0];
    NSMutableArray *phonesName = [NSMutableArray arrayWithCapacity:0];
        if(![[info objectForKey:[NSString stringWithFormat:@"phone%d",i]] isKindOfClass:[NSNull class]])
        {
            [phones addObject:[info objectForKey:[NSString stringWithFormat:@"phone%d",0]]];
            [phonesName addObject:[NSString stringWithFormat:@"phone%d",0]];
        }
   
    
    if(phones.count != 0 || phonesName.count != 0)
    {
        // ABMultiValueRef类似是Objective-C中的NSMutableDictionary
        ABMultiValueRef mv = ABMultiValueCreateMutable(kABMultiStringPropertyType);
        // 添加电话号码与其对应的名称内容
        for (int i = 0; i < [phones count]; i ++) {
            ABMultiValueIdentifier mi = ABMultiValueAddValueAndLabel(mv, (__bridge CFStringRef)[phones objectAtIndex:i], (__bridge CFStringRef)[phonesName objectAtIndex:i], &mi);
        }
        // 设置phone属性
        ABRecordSetValue(person, kABPersonPhoneProperty, mv, NULL);
    }
    
    //写入邮箱
    if([info objectForKey:@"email"])
    {
       
        ABMultiValueRef em = ABMultiValueCreateMutable(kABPersonEmailProperty);
        ABMultiValueIdentifier ma = ABMultiValueAddValueAndLabel(em, (__bridge CFTypeRef)([info objectForKey:@"email"]), (__bridge CFStringRef)@"email", &ma);
        ABRecordSetValue(person, kABPersonEmailProperty, em, NULL);
    }
//
//    //写入网址
//    if([info objectForKey:@"url"])
//    {
//        NSMutableArray *y = [NSMutableArray arrayWithObjects:[info objectForKey:@"url"],@"http://www.ucardpro.com", nil];
//        NSMutableArray *z = [NSMutableArray arrayWithObjects:@"个人主页",@"Ucard官网", nil];
//        ABMultiValueRef url = ABMultiValueCreateMutable(kABPersonURLProperty);
//        for (int i = 0; i < [phones count]; i ++) {
//            ABMultiValueIdentifier ur = ABMultiValueAddValueAndLabel(url, (__bridge CFStringRef)[y objectAtIndex:i], (__bridge CFStringRef)[z objectAtIndex:i], &ur);
//        }
//        ABRecordSetValue(person, kABPersonURLProperty, url, NULL);
//    }
//
//    //写入日期
//    NSDate *date = [NSDate date];
//    NSDateFormatter *f = [[NSDateFormatter alloc] init];
//    f.dateFormat = @"yyyy年MM月dd日 HH:mm:SS";
//    NSString *s = [NSString stringWithFormat:@"名片导入时间:%@   导入来自Ucard",[f stringFromDate:date]];
//    NSLog(@"%@",s);
//    ABRecordSetValue(person,kABPersonNoteProperty, (__bridge CFTypeRef)(s), NULL);
    
    //写入前检查是否联系人已存在
    if([ZxkSetAddressBook examineAddressWithName:firstName] == NO)
    {
        block();
        return NO;
    }
    // 获取通讯录中所有的联系人
    NSArray *array = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
    // 遍历所有的联系人并删除
    for (id obj in array) {
        ABRecordRef people = (__bridge ABRecordRef)obj;
        NSString *first = (__bridge NSString *)ABRecordCopyValue(people, kABPersonFirstNameProperty);
        if ([first isEqualToString:firstName])
        {
            ABAddressBookRemoveRecord(addressBook, people, nil);
        }

    }
    
    // 将新建的联系人添加到通讯录中
    ABAddressBookAddRecord(addressBook, person, NULL);
    
    if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {

                dispatch_semaphore_signal(sema);
            
        });
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    }
    else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
        // The user has previously given access, add the contact
        if(ABAddressBookSave(addressBook, NULL))
        {
            return YES;
            
        }
    }
    else {
        // The user has previously denied access
        // Send an alert telling user to change privacy setting in settings app
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"导入失败,请在设置-隐私中检查是否有权限访问您的通讯录" delegate:self cancelButtonTitle:@"确认" otherButtonTitles:nil];
        [alert show];
    }
    return NO;
}


以下是B的加密操作,部分核心代码有删减

//通讯录加密
-(void)encryptWithAccountList:(AccountList *)list RePetBlock:(void(^)(void))block
{
    if([ZxkSetAddressBook SetAddressBookWithInfo:[dic mutableCopy] RePetBlock:block] == YES)
    {
        if(self.delegate && [self.delegate respondsToSelector:@selector(setAddressSuccess:)])
        {
            [self.delegate setAddressSuccess:self.accountList.remark];
        }
    }
}


最后是A的按钮交互代码
-(void)buttonClick


__block NSArray *arr = self.p_tableArr;
        __block int select = self.p_didSelect;
        __block AccountViewController *v = self;
        __block UIAlertView *alt;
        [self.encrypt encryptWithAccountList:[self.p_tableArr objectAtIndex:self.p_didSelect] RePetBlock:^
         {
             self.p_alertBlock = ^(NSInteger buttonIndex)
             {
                 
                 if(buttonIndex==1)
                 {
                     AccountList *list = [arr objectAtIndex:select];
                     [v setAddressSuccess:list.remark];
                 }
             };
             alt = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"tip",nil) message:NSLocalizedString(@"setaddressTips", nil) delegate:v cancelButtonTitle:NSLocalizedString(@"cancel", nil) otherButtonTitles:NSLocalizedString(@"ok",nil), nil];
             [alt show];
             
         }];



以下是B的结果回调代理 部分核心代码有删减

#pragma mark - AddressbookEncryptDelegate
- (void)setAddressSuccess:(NSString *)firstName
{

    
    [self.navigationController pushViewController:self.p_peoplePicker animated:YES];
   
}





   以上实现既有代理也有Block,可以看到代理实现的过程较为繁杂,而Block实现更加的便捷直观,根据上一章节在Block中讲到的系统 UIAlertView的集中代码用法,这一整个过程不需要任何的回调代理,也不需要任何的逻辑判断,实际上只需三个Block代码快就可以完成,第一个 是处理UIAlertView交互的bLOCK,一个是处理三种结果情况的Block,一个是组合前两个Block之后的最终Block。
  也许从实现来看,三种方法都可以达到目的,但是在MVC的思维中前两种实现方法都存在M层越界的情况。
  在这个过程中,作为数据层,B的职责只是加密,C的职责只是导入,A作为Controller层主要是想拿到C的处理结果来做下一步的逻辑。第一种方案和 第二种方案的实现中,由于C都是把自己的结果先交给B,B再交给A,所以这里存在A把自己与B无关的机密信息泄漏给了B,因为是B先知道这三种结果,A后 知道。所以从理论来讲,这里可能会存在B操作不当没有正确的把C的结果告知A。当然,由于以上过程较为简单,一般不会出现这种情况。而由于C作为一个工具 类的静态方法,无法做到代理告知,这也是一个问题。
 
  Block语法在这个过程中的好处就是:当Controller的某一个命令需要多个Model层协调进行的时候,Controller只需要将自己对最 终结果处理的逻辑代码写在这个命令传达之前,并且准确的交由真正那个能够给自己明确答复的Model层去直接执行命令,既能够集中自己的逻辑代码,也避免 了其他M层作为传声筒传递结果的重复代码。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值