您的位置:首页 > 其它

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

2015-09-01 10:40 363 查看
在项目开发中,经常避免一些与系统工具交互的功能需求。比如说开启蓝牙,开启相机,通讯录功能,还有数据加密等等。

由于这些功能的实现没有实例化的必要,并且又是许多项目都共用的功能,所以一般我们会作为类的静态方法去作为自己的工具类。

以下是一段将字典的键值对导入通讯录的静态方法代码。

假如说现在有一个这样的逻辑流程,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层作为传声筒传递结果的重复代码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: