iOS 中的链式编程函数式编程入门
Posted 昊卓集团
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS 中的链式编程函数式编程入门相关的知识,希望对你有一定的参考价值。
iOS 中的链式编程、函数式编程入门
对一个程序猿来说,从一开始接触编程后会逐渐经历好几个不同的编程思想。包括过程式编程、面向对象编程、响应式编程、函数式编程、链式编程等等。
过程式编程
的特点是随着程序的编写逐步进行,写到哪儿运行到哪儿。
面向对象
的特点是万物皆对象。很著名的例子:把大象放进冰箱。
响应式编程
的特点是一方触发,多方响应。OC中的KVO、通知中心就是这种。触发者只负责触发,不理会结果。
函数式编程
的特点是将函数作为一等公民,当作参数和返回值使用。典型的如OC和Swift 中的 map函数、fiflt函数、reduce函数等。每个函数的处理结果给到下一个函数,最后的结果由自身函数调出。
链式编程
的特点是运用点语法将很多个函数串联起来。典型的例子是OC中的Masnary和Swift 中的Snpkit。
这篇文章主要介绍函数式编程和链式编程的实现
链式编程
链式编程的特点是使用点语法将对象的多个函数连起来调用。就像这样
obj.func1(par).func2
(par).func3(par)
以一个例子来实现。假设我需要做一个字符串处理的扩展,其中包涵拼接字符
、删除最后一个字符
、修改最后一个字符
这三个功能。在OC和Swift 中,这些函数都有现成,但是我想它们能够联合起来调用。假设我已经给这三个函数分别去名字叫:addString
,
removeLastString
,
alterLastString
.
而我想像下面这样调用:
NSString *str = @
"abcdefg";
NSString *newStr = str.
addString(@"123").
removeLastString().add
(@"555"). alter
LastString
("*") NSLog(@"%@",
newStr );
最后输出的结果是:abcdefg1255*
.这个应该很容易理解了。
接下来我分别使用OC和Swift来实现。
在OC中(链式编程)
新建一个工具类StringManegeTool
,这个类包涵了一个初始化的函数:initWithString
以及一个启动函数doSomething.并且包含了若干个block做为属性,以便使用点语法。
//// StringManegeTool.h
// funTest//// Created
by JD on 2017/11/4.//
Copyright © 2017年 JD.
All rights reserved.//
#import <Foundation/
Foundation.h>@class
StringManegeTool;typedef
StringManegeTool* (^
TESTBlock1)(NSString*);
typedef StringManegeTool*
(^TESTBlock2)(void);
@interface
StringManegeTool:
NSObject- (instancetype)
initWithString:(NSString*)
str; - (NSString*)doSomething:
(void (^)(StringManegeTool
*))maker;@property
(nonatomic,copy)
TESTBlock1
addString;@property
(nonatomic,copy)
TESTBlock2
removeLastString;@property
(nonatomic,copy)
TESTBlock1
alertLastString;@end
.m文件中实现。在初始化方法中实现了block,并且在doSomthing中实现了调用block。
//// StringManegeTool.m
// funTest//// Created
by JD on 2017/11/4.//
Copyright © 2017年 JD.
All rights reserved.//
#import "StringManegeTool.
h"#import <Foundation/
Foundation.h>@interface
StringManegeTool ()
@property(nonatomic,
strong) NSMutableString*
buffStr;@end@
implementation
StringManegeTool-
(instancetype)
initWithString
:(NSString*)str{ self =
[super init]; if (self)
{ self.buffStr =
[[NSMutableString alloc]
initWithString:str]; __weak
StringManegeTool *weakSelf
= self; self.addString
= ^StringManegeTool *
(NSString *str) { [weakSelf.
buffStr appendString:
str]; return
weakSelf; }; self.
removeLastString =
^StringManegeTool *{ [weakSelf.
buffStr
deleteCharactersInRange:
NSMakeRange(weakSelf.
buffStr.length-1, 1)];
return weakSelf; }; self.alertLastString
= ^StringManegeTool
*(NSString *str) { [weakSelf.
buffStr
replaceCharactersInRange
:NSMakeRange(weakSelf.
buffStr.length-1, 1)
withString:str];
return weakSelf; }; } return self; } - (NSString*)doSomething:
(void (^)
(StringManegeTool
*))maker{ maker(self);
return self.buffStr; }@end
接下来我可以这样调用:
StringManegeTool *tool
= [[StringManegeTool
alloc] initWithString:
@"abcdefg"]; NSString *newStr =
[tool doSomething:^
(StringManegeTool
*make) { make.addString(
@"123").removeLastString
().addString(@"555").
alertLastString(@"*"); }]; NSLog(@"%@",newStr); 打印结果//2017-11-04
15:36:08.495 funTest[1661:
121049] abcdefg1255*
回忆一下Masnary。熟悉的味道!
再来看看Swift中如何实现链式编程
////StringManegeTool-
InSwift.swift//
funTest//// Created
by JD on 2017/11/4.//
Copyright © 2017年 JD.
All rights reserved.
//import UIKitclass
StringManegeToolInSwift:
NSObject { var bufStr:String =
String() convenience init(_
withString:String){
self.init();
self.bufStr = withString } func doSomething(_ make:
(StringManegeToolInSwift)
->())->String{ make(self)
return self.bufStr } func addString(_
string:String)->
StringManegeToolInSwift
{ self.bufStr.append
(string) return self } func remoLastString()->
StringManegeToolInSwift{ let end = self.
bufStr.endIndex let start = self.
bufStr.index(before: end) self.bufStr.
removeSubrange
(start..<end)
return self } func alertLastString(_
string:String) ->
StringManegeToolInSwift{ let end = self.bufStr.
endIndex let start = self.bufStr.
index(before: end)
self.bufStr.
replaceSubrange
(start..<end, with:
string)
return self } /// 调用 class func actionDo(){ let tool =
StringManegeToolInSwift.
init("abcdefg") let newString =
tool.doSomething {
(maker) in maker.addString("123")
.remoLastString()
.addString
("555").alertLastString
("*")} print(newString) }//打印: abcdefg1255* }
说实话,Swift写起来要简单太多了。
总结一下:ios中,链式编程的特点是调用返回值为自身的函数或者Block。再结合map等函数的映射转换,这样可以使得代码变的非常灵活。
函数式编程
我之前一直把函数式编程理解为高阶函数,其实这就是高阶函数。先看一个很典型的例子,照样,我们从CO开始。
NSArray<NSString*>
*arr = @[@"252",@"55541",
@"2295",@"21"]; arr = [arr
sortedArrayUsingComparator
:^NSComparisonResult(
NSString* _Nonnull obj1,
NSString* _Nonnull obj2
) { return obj1.
length < obj2.length; }]; NSLog(@"%@",arr); 打印:2017-11-04 16:41:
22.846
funTest[2478:150288] (
252, 55541, 2295,
21)
这是一个数组排序的函数。我们经常把在函数中使用函数作为参数称作高阶函数(这实际上就是函数式编程的一种特质)。上面的排序函数中,我们将两个数组内的元素比较的结果拿来使用给我本体函数,实现排序的目的。下面这个函数可能回更加复杂一点:
NSString *result =
[self testWithStr:@"adcf"
One:^BOOL(NSString *str)
{return [str
isEqualToString
:@"111"]; } two:^NSString *(BOOL
abool) { return abool?
@"相等":@"不相等"; }]; NSLog
(@"%@",result); //打印: 2017-11-08 09:24:49.
011487+0800 funTest[7487
:1779986] 不相等
它是一个字符判断函数,在第一个参数中,我们输入想要比较的字符,在第一个block中进行比较并返回一个bool值,这个bool值将使用在第二个block的参数中,第二个block是根据bool值返回需要比较的两个字符是否相等的描述。
那具体是怎么实现的呢? 根据这个函数的特点,第一个block的调用结果将被用在第二个block上,对于第二个block来讲,他的参数本身就不是固定的,而是由第一个block决定,由此我们应该能想到,第二个block的参数其实就是第一个block才对。实现如下:
- (NSString *)testWithStr
:(NSString *)str One:
(BOOL(^)(NSString* str))
one two:(NSString*(^)
(BOOL abool))Two{
return Two(one(str)); }
如果是Swift,其实是及其相似的:
func testWith(Str:String,
one:(String)->Bool,two:
(Bool)->String) -> String
{ return two(one
(Str)) }//调用self.testWith
(Str: "abc", one: { (str
) -> Bool in return str ==
"123" }) { (abool) ->
String in return abool?
"相等":"不相等" }
这里的确是函数式编程, 但是我们发现其中多了东西:虽然这里将一些函数作为另一函数的参数,但是,这些函数的返回值和参数都具有一定的关联,没错,上面的函数中,block one
的返回值的类型恰恰是block two
的参数类型。他们有一些必然的联系。这就涉及到了响应式编程
的范畴,这里其实算是响应式函数编程
,不在本文的范畴之内,有兴趣的可以自行了解,本文不做介绍.
但是无可厚非的是,这里我们可以看到函数式编程的特点:将函数做为参数来使用,这就使得函数本身具备更大的灵活性,通过参数函数适应不同的应用场景。
将函数配合泛型,又能继续扩大函数的灵活性。下面修改一下上面的例子看看泛型中的函数式编程:
func testWith<T:Comparable
>(_ obj:T, one:(T)->Bool,
two:(Bool)->String) ->
String { return
two(one(obj)) }
调用
let result = tool.
testWith("abc", one:
{ (str) -> Bool in return str
== "123" }) { (abool) -
> String in guard abool
else{
return "不相等" }
return "相等" } print(result) let result2 =
tool.testWith(5,
one: { (int) ->
Bool in return int
== 5 }) { (abool)
-> String in guard abool
else{
return "不相等" }
return "相等" } print(result2)
以上就是函数式编程结合泛型。
提一下我们经常听到的RAC,这是一个响应式函数编程,同时也会使用到泛型。 关于响应式编程, 我会在以后的文章中写出,同时将包含RAC的知识。
以上是关于iOS 中的链式编程函数式编程入门的主要内容,如果未能解决你的问题,请参考以下文章