iOS 中的鏈?zhǔn)骄幊绦跫恰⒑瘮?shù)式編程入門

對(duì)一個(gè)程序猿來說,從一開始接觸編程后會(huì)逐漸經(jīng)歷好幾個(gè)不同的編程思想紧憾。包括過程式編程到千、面向?qū)ο缶幊獭㈨憫?yīng)式編程赴穗、函數(shù)式編程、鏈?zhǔn)骄幊痰鹊取?/p>

過程式編程的特點(diǎn)是隨著程序的編寫逐步進(jìn)行膀息,寫到哪兒運(yùn)行到哪兒般眉。

面向?qū)ο?/code>的特點(diǎn)是萬物皆對(duì)象。很著名的例子:把大象放進(jìn)冰箱潜支。

響應(yīng)式編程的特點(diǎn)是一方觸發(fā)甸赃,多方響應(yīng)。OC中的KVO冗酿、通知中心就是這種埠对。觸發(fā)者只負(fù)責(zé)觸發(fā),不理會(huì)結(jié)果裁替。

函數(shù)式編程的特點(diǎn)是將函數(shù)作為一等公民项玛,當(dāng)作參數(shù)和返回值使用。典型的如OC和Swift 中的 map函數(shù)弱判、fiflt函數(shù)襟沮、reduce函數(shù)等。每個(gè)函數(shù)的處理結(jié)果給到下一個(gè)函數(shù)昌腰,最后的結(jié)果由自身函數(shù)調(diào)出开伏。

鏈?zhǔn)骄幊?/code>的特點(diǎn)是運(yùn)用點(diǎn)語法將很多個(gè)函數(shù)串聯(lián)起來。典型的例子是OC中的Masnary和Swift 中的Snpkit遭商。

這篇文章主要介紹函數(shù)式編程和鏈?zhǔn)骄幊痰膶?shí)現(xiàn)

鏈?zhǔn)骄幊?/h4>

鏈?zhǔn)骄幊痰奶攸c(diǎn)是使用點(diǎn)語法將對(duì)象的多個(gè)函數(shù)連起來調(diào)用固灵。就像這樣

    obj.func1(par).func2(par).func3(par)

以一個(gè)例子來實(shí)現(xiàn)。假設(shè)我需要做一個(gè)字符串處理的擴(kuò)展劫流,其中包涵拼接字符巫玻、刪除最后一個(gè)字符丛忆、修改最后一個(gè)字符這三個(gè)功能。在OC和Swift 中大审,這些函數(shù)都有現(xiàn)成蘸际,但是我想它們能夠聯(lián)合起來調(diào)用。假設(shè)我已經(jīng)給這三個(gè)函數(shù)分別去名字叫:addString, removeLastString,alterLastString.而我想像下面這樣調(diào)用:

  NSString *str = @"abcdefg"徒扶;
  NSString *newStr = str. addString(@"123").removeLastString().add(@"555"). alter LastString("*")
  NSLog(@"%@",newStr )粮彤;

最后輸出的結(jié)果是:abcdefg1255*.這個(gè)應(yīng)該很容易理解了。
接下來我分別使用OC和Swift來實(shí)現(xiàn)姜骡。

在OC中(鏈?zhǔn)骄幊蹋?/h5>

新建一個(gè)工具類StringManegeTool导坟,這個(gè)類包涵了一個(gè)初始化的函數(shù):initWithString以及一個(gè)啟動(dòng)函數(shù)doSomething.并且包含了若干個(gè)block做為屬性,以便使用點(diǎn)語法圈澈。

//
//  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文件中實(shí)現(xiàn)惫周。在初始化方法中實(shí)現(xiàn)了block,并且在doSomthing中實(shí)現(xiàn)了調(diào)用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

接下來我可以這樣調(diào)用:

 StringManegeTool *tool = [[StringManegeTool alloc] initWithString:@"abcdefg"];  
 NSString *newStr = [tool doSomething:^(StringManegeTool *make) {
        make.addString(@"123").removeLastString().addString(@"555").alertLastString(@"*");
    }];
    
 NSLog(@"%@",newStr);

打印結(jié)果
//2017-11-04 15:36:08.495 funTest[1661:121049] abcdefg1255*

回憶一下Masnary递递。熟悉的味道!

再來看看Swift中如何實(shí)現(xiàn)鏈?zhǔn)骄幊?/h5>
//
//  StringManegeToolInSwift.swift
//  funTest
//
//  Created by JD on 2017/11/4.
//  Copyright ? 2017年 JD. All rights reserved.
//

import UIKit

class 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
    }
    
    /// 調(diào)用
    class func actionDo(){
        let tool = StringManegeToolInSwift.init("abcdefg")
        
        let newString = tool.doSomething { (maker) in
            maker.addString("123").remoLastString().addString("555").alertLastString("*")
        }        
        print(newString)
    }
//打由睹础:
         abcdefg1255*
}

說實(shí)話登舞,Swift寫起來要簡(jiǎn)單太多了。

總結(jié)一下:iOS中悬荣,鏈?zhǔn)骄幊痰奶攸c(diǎn)是調(diào)用返回值為自身的函數(shù)或者Block菠秒。再結(jié)合map等函數(shù)的映射轉(zhuǎn)換,這樣可以使得代碼變的非常靈活氯迂。

函數(shù)式編程

我之前一直把函數(shù)式編程理解為高階函數(shù)践叠,其實(shí)這就是高階函數(shù)。先看一個(gè)很典型的例子嚼蚀,照樣禁灼,我們從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
)

這是一個(gè)數(shù)組排序的函數(shù)匾二。我們經(jīng)常把在函數(shù)中使用函數(shù)作為參數(shù)稱作高階函數(shù)(這實(shí)際上就是函數(shù)式編程的一種特質(zhì))。上面的排序函數(shù)中拳芙,我們將兩個(gè)數(shù)組內(nèi)的元素比較的結(jié)果拿來使用給我本體函數(shù)察藐,實(shí)現(xiàn)排序的目的。下面這個(gè)函數(shù)可能回更加復(fù)雜一點(diǎn):

 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] 不相等

它是一個(gè)字符判斷函數(shù)分飞,在第一個(gè)參數(shù)中,我們輸入想要比較的字符睹限,在第一個(gè)block中進(jìn)行比較并返回一個(gè)bool值譬猫,這個(gè)bool值將使用在第二個(gè)block的參數(shù)中讯檐,第二個(gè)block是根據(jù)bool值返回需要比較的兩個(gè)字符是否相等的描述。
那具體是怎么實(shí)現(xiàn)的呢染服? 根據(jù)這個(gè)函數(shù)的特點(diǎn)别洪,第一個(gè)block的調(diào)用結(jié)果將被用在第二個(gè)block上,對(duì)于第二個(gè)block來講柳刮,他的參數(shù)本身就不是固定的挖垛,而是由第一個(gè)block決定,由此我們應(yīng)該能想到秉颗,第二個(gè)block的參數(shù)其實(shí)就是第一個(gè)block才對(duì)痢毒。實(shí)現(xiàn)如下:

- (NSString *)testWithStr:(NSString *)str  One: (BOOL(^)(NSString* str))one two:(NSString*(^)(BOOL abool))Two{
    return Two(one(str));
}

如果是Swift,其實(shí)是及其相似的:

func testWith(Str:String, one:(String)->Bool,two:(Bool)->String) -> String {
        return two(one(Str))
    }
//調(diào)用
self.testWith(Str: "abc", one: { (str) -> Bool in
            return str == "123"
        }) { (abool) -> String in
            return abool?"相等":"不相等"
        }

這里的確是函數(shù)式編程蚕甥, 但是我們發(fā)現(xiàn)其中多了東西:雖然這里將一些函數(shù)作為另一函數(shù)的參數(shù)哪替,但是,這些函數(shù)的返回值和參數(shù)都具有一定的關(guān)聯(lián)菇怀,沒錯(cuò)凭舶,上面的函數(shù)中,block one的返回值的類型恰恰是block two的參數(shù)類型爱沟。他們有一些必然的聯(lián)系库快。這就涉及到了響應(yīng)式編程的范疇,這里其實(shí)算是響應(yīng)式函數(shù)編程钥顽,不在本文的范疇之內(nèi),有興趣的可以自行了解靠汁,本文不做介紹.
但是無可厚非的是蜂大,這里我們可以看到函數(shù)式編程的特點(diǎn):將函數(shù)做為參數(shù)來使用,這就使得函數(shù)本身具備更大的靈活性蝶怔,通過參數(shù)函數(shù)適應(yīng)不同的應(yīng)用場(chǎng)景奶浦。
將函數(shù)配合泛型,又能繼續(xù)擴(kuò)大函數(shù)的靈活性踢星。下面修改一下上面的例子看看泛型中的函數(shù)式編程:

func testWith<T:Comparable>(_ obj:T, one:(T)->Bool,two:(Bool)->String) -> String {
        return two(one(obj))
    }

調(diào)用

 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)

以上就是函數(shù)式編程結(jié)合泛型澳叉。

提一下我們經(jīng)常聽到的RAC,這是一個(gè)響應(yīng)式函數(shù)編程沐悦,同時(shí)也會(huì)使用到泛型成洗。 關(guān)于響應(yīng)式編程, 我會(huì)在以后的文章中寫出藏否,同時(shí)將包含RAC的知識(shí)瓶殃。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市副签,隨后出現(xiàn)的幾起案子遥椿,更是在濱河造成了極大的恐慌基矮,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冠场,死亡現(xiàn)場(chǎng)離奇詭異家浇,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)碴裙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門钢悲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人青团,你說我怎么就攤上這事譬巫。” “怎么了督笆?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵芦昔,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我娃肿,道長(zhǎng)咕缎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任料扰,我火速辦了婚禮凭豪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘晒杈。我一直安慰自己嫂伞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布拯钻。 她就那樣靜靜地躺著帖努,像睡著了一般。 火紅的嫁衣襯著肌膚如雪粪般。 梳的紋絲不亂的頭發(fā)上拼余,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音亩歹,去河邊找鬼匙监。 笑死,一個(gè)胖子當(dāng)著我的面吹牛小作,可吹牛的內(nèi)容都是我干的亭姥。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼躲惰,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼致份!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起础拨,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤氮块,失蹤者是張志新(化名)和其女友劉穎绍载,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滔蝉,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡击儡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蝠引。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阳谍。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖螃概,靈堂內(nèi)的尸體忽然破棺而出矫夯,到底是詐尸還是另有隱情,我是刑警寧澤吊洼,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布训貌,位于F島的核電站,受9級(jí)特大地震影響冒窍,放射性物質(zhì)發(fā)生泄漏递沪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一综液、第九天 我趴在偏房一處隱蔽的房頂上張望款慨。 院中可真熱鬧,春花似錦谬莹、人聲如沸檩奠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽笆凌。三九已至,卻和暖如春士葫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背送悔。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工慢显, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人欠啤。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓荚藻,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親洁段。 傳聞我的和親對(duì)象是個(gè)殘疾皇子应狱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容