以前觉得这种标题有点偏向于理论,实际开发中怎么会有这种诡异的需求,但是真正遇到了这种硬需求时觉得还是有那么点价值的,理论付诸了实践在此也就做了个整理。

以我私下开发中的一处代码为例,本意是希望有这么一个方法:能够传入一个开始标记(NSString*)一个结束标记(NSString*)一段文字(NSString*)  然后内部在文字中扫描并返回标记包裹内容的范围(NSRange这个范围是忽视标记的)这个范围可能会有多个所以返回的应该是一个装着range的数组。并且顺便把原来字符串中的开始和结束标记全过滤掉,把过滤后的字符串也返回出来。

举个例子就是:传入开始标记“<” 结束标记“>” 一段文字 “会议需要叫上<彼得>和<罗宾>”   然后希望返回一个数组 [{location:6,length:2},{location:9,length:2}] ,和返回处理后的字符串“会议需要叫上彼得和罗宾”。

代码希望能够写成这样,但是是不可能的。

- (NSArray *,NSMutableString *)scanBeginStr:(NSString *)beginstr endStr:(NSString *)endstr inText:(NSMutableString *)text

好下面提供三种途径完成此需求。  

1.使用字典

这种方法是最low但是最容易理解的,就是如果你需要返回多个对象,直接将多个对象塞在一个字典里面自己设置合理的key并返回字典,字典里面可以放任意数量的“返回值”。

- (NSDictionary *)scanBeginStr:(NSString *)beginstr endStr:(NSString *)endstr inText:(NSMutableString *)text{
NSRange range1,range2;
NSUInteger location =0,length=0;
range1.location = 0;
NSMutableArray *rangeArray = [NSMutableArray array];
while (range1.location != NSNotFound) {
range1 = [text rangeOfString:beginstr];
range2 = [text rangeOfString:endstr];
if (range1.location != NSNotFound) {
location = range1.location;
length = range2.location - range1.location - 1;
if (length > 5000)break;
[text replaceOccurrencesOfString:beginstr withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, range1.location + range1.length)];
[text replaceOccurrencesOfString:endstr withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, range2.location + range2.length - 1)];
}
[rangeArray addObject:@{@"location":@(location),@"length":@(length)}];
}
return @{@"rangeArray":rangeArray,@"text":text};
}

这个方法在调用时也就是这样了,非常朴实的代码。

    NSDictionary* result = [self scanBegin2Str:@"<" endStr:@">" inText:mutableText];
NSArray *rangeArray = result[@"rangeArray"];
NSMutableString *text = [result[@"text"] mutableCopy];

如果觉得字典不舒服也完全可以用模型,自定义一个对象然后给这个对象的各个属性赋值然后再把这个自定义对象返回回去,虽然代码看上去更科学一点但是需要写一些额外的代码并且不能实现任意可配置(每一种属性都必须要提前设定好),这个和上面算是一个相同的思路就不单独再列一条说了。

2.使用指针的指针

这种方法是我实际使用的方法,就是把需要修改的text的指针的指针传进去,然后在方法的内部对这个实参取一下值得到text的指针。然后通过这个指针修改外部的变量的值。代码实现如下

- (NSArray *)scanBeginStr:(NSString *)beginstr endStr:(NSString *)endstr inText:(NSMutableString * *)textPointer{
NSRange range1,range2;
NSUInteger location =0,length=0;
range1.location = 0;
NSMutableString *text = *textPointer;
NSMutableArray *rangeArray = [NSMutableArray array];
while (range1.location != NSNotFound) {
range1 = [text rangeOfString:beginstr];
range2 = [text rangeOfString:endstr];
if (range1.location != NSNotFound) {
location = range1.location;
length = range2.location - range1.location - 1;
if (length > 5000)break;
[text replaceOccurrencesOfString:beginstr withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, range1.location + range1.length)];
[text replaceOccurrencesOfString:endstr withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, range2.location + range2.length - 1)];
}
[rangeArray addObject:@{@"location":@(location),@"length":@(length)}];
}
return rangeArray;
}

这个方法在调用时就这么写了,因为mutabletext的修改是无声无息的。

    NSArray *rangeArray = [self scanBegin3Str:@"<" endStr:@">" inText:&mutableText];
// 董铂然博客园

  

3.使用block回调

这种方法实际上严格意义来说不能算返回值,但是能够实现返回值的效果。

- (void)scanBeginStr:(NSString *)beginstr endStr:(NSString *)endstr inText:(NSMutableString *)text result:(void(^)(NSArray *rangeArray,NSMutableString *text))result{
NSRange range1,range2;
NSUInteger location =0,length=0;
range1.location = 0;
NSMutableArray *rangeArray = [NSMutableArray array];
while (range1.location != NSNotFound) {
range1 = [text rangeOfString:beginstr];
range2 = [text rangeOfString:endstr];
if (range1.location != NSNotFound) {
location = range1.location;
length = range2.location - range1.location - 1;
if (length > 5000)break;
[text replaceOccurrencesOfString:beginstr withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, range1.location + range1.length)];
[text replaceOccurrencesOfString:endstr withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, range2.location + range2.length - 1)];
}
[rangeArray addObject:@{@"location":@(location),@"length":@(length)}];
}
result(rangeArray,text);
}

这个block在使用时可能比较特殊就这么写了

    [self scanBeginStr:@"<" endStr:@">" inText:mutabletext result:^(NSArray *rangeArray, NSMutableString *text) {
NSLog(@"%@,%@",rangeArray,text);
}];

如果把block的返回值写成一个字典或是模型也可以,但是那就多此一举了。 返回值不能尝试结构体类型,结构体内不能用OC对象只能用基本数据类型。

其实感觉还有别的方法,比如设置N个成员变量在方法内部计算后重新set也完全可以,但是可能大家也知道成员变量多了比较恶心。最近比较火的函数式编程一直在倡导“方法内不能产生副作用”“实现引用透明” ,如果这么看那后两种方法就不符合FP的规则了,但是用着也有自己的特色。

转载需注明出处 ,原文链接

  

iOS用三种途径实现一方法有多个返回值的更多相关文章

  1. iOS 的三种自建证书方法https请求相关配置

    如果你的app服务端安装的是SLL颁发的CA,可以使用系统方法直接实现信任SSL证书,关于Apple对SSL证书的要求请参考:苹果官方文档CertKeyTrustProgGuide 这种方式不需要在B ...

  2. Java线程实现的第三种方式Callable方式与结合Future获取返回值

    多线程的实现方式有实现Runnable接口和继承Thread类(实际上Thread类也实现了Runnable接口),但是Runnable接口的方式有两个弊端,第一个是不能获取返回结果,第二个是不能抛出 ...

  3. iOS 三种收起键盘的方法

    - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typica ...

  4. 【读书笔记】iOS-开发技巧-三种收起键盘的方法

    - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typica ...

  5. iOS的三种多线程技术NSThread/NSOperation/GCD

    1.iOS的三种多线程技术 1.NSThread 每个NSThread对象对应一个线程,量级较轻(真正的多线程) 2.以下两点是苹果专门开发的"并发"技术,使得程序员可以不再去关心 ...

  6. C#生成XML的三种途径

    C#生成XML的三种途径 为了全面,这里都将XML保存到文件中,有三种生成XML的方式: 1.我认为是最原始,最基本的一种:利用XmlDocument向一个XML文件里写节点,然后再利用XmlDocu ...

  7. File类三种得到路径的方法

    转: File类三种得到路径的方法 2010年11月29日 20:37:00 ssyan 阅读数:27123 标签: filemicrosoftstringexceptionwindowsunix   ...

  8. 【转】python 三种遍历list的方法

    [转]python 三种遍历list的方法 #!/usr/bin/env python # -*- coding: utf-8 -*- if __name__ == '__main__': list ...

  9. 【Java 线程的深入研究1】Java 提供了三种创建线程的方法

    Java 提供了三种创建线程的方法: 通过实现 Runnable 接口: 通过继承 Thread 类本身: 通过 Callable 和 Future 创建线程. 1.通过实现 Runnable 接口来 ...

随机推荐

  1. java中两种添加监听器的策略

    /*第一种:将事件的处理委托给其他对象,下面的例子是委托给了MyListener(implements ActionListener)*/ 1 import java.applet.Applet; i ...

  2. SubSonic3.0插件分页查询速度测试

    使用SubSonic3.0一段时间了,一直都想找机会测试一下各种查询分页速度,对比一下插件的查询效率到底怎么样,所以昨天写好了测试程序,准备好1K.1W.10W.50W和100W记录的数据表,早上详细 ...

  3. git配置

    安装完成git之后基本就可以使用了,但是,有些配置还是需要的. 在任何一个目录下,右键 Git Bash Here, 然后输入: 1.设置用户名和邮箱 $ git config --global us ...

  4. 【Bug】看不见的分隔符: Zero-width space

    今天在调试一段代码的时候,有一个输入不能为空的库函数抛出了异常(为空就会抛出异常,就是这么傲娇).自己暗骂了自己一番,怎么这么大意,于是追溯源头,开始寻找输入控制的地方.但是当我找到时我惊呆了,我明明 ...

  5. 做一个会使用PS的前端开发

    做前端开发的需不需要PS 记得在之前的老东家做某一个系统开发,当时正在做界面开发,发现界面还需要添加几个图标,于是把这个需求反馈给了项目经理.过了十几分钟,项目经理跑过来告诉我:产品部的UI设计人员( ...

  6. iOS 视图与视图层次结构(内容根据iOS编程)

    视图基础 视图是 UIView 对象,或者其子对象. 视图知道如何绘制自己. 视图可以处理事件,例如触摸(touch). 视图会按照层次结构排列,位于视图层次结构顶端的是应用窗口. 视图层次结构 任何 ...

  7. .Net语言 APP开发平台——Smobiler学习日志:如何在手机上开发仪表盘控件

    最前面的话:Smobiler是一个在VS环境中使用.Net语言来开发APP的开发平台,也许比Xamarin更方便 一.目标样式 我们要实现上图中的效果,需要如下的操作: 1.从工具栏上的"S ...

  8. iOS阶段学习第34天笔记(UI小组件 UISegment-UISlider-UIStepper-UIProgressView-UITextView介绍)

    iOS学习(UI)知识点整理 一.UI小组件 1.UISegmentedControl 分段选择器  实例代码 - (void)viewDidLoad { [super viewDidLoad]; / ...

  9. ComponentOne 2016 V3 发布

    ComponentOne Studio Enterprise 2016 V3 新特性 我们很高兴的宣布ComponentOne 2016 V3发布了!2016 Connect开发者大会上微软发布了Vi ...

  10. nodejs 遍历数组的两种方法

    var array = [1,2,3]; array.forEach(function(v,i,a){ console.log(v); console.log(i); console.log(a); ...