開発におけるいくつかの経験

18958 ワード

1.ReactiveCocoaの概要
ReactiveCocoa(略称RAC)は、iOSやOSに応用されたGithubからオープンソースの新しいフレームワークであり、Cocoaはアップルのフレームワーク全体の略称であるため、多くのアップルのフレームワークはCocoaで終わるのが好きである.
2.ReactiveCocoa作用
  • iOSの開発では、いくつかのイベントが応答すると、いくつかのビジネスロジックを処理する必要があります.これらのイベントは異なる方法で処理されます.
  • 例えばボタンのクリックはaction,ScrolViewスクロールはdelegate,属性値はKVOなどのシステムで提供される方式を変更する.
  • 実際にはこれらのイベントは、RACによって
  • を処理することができる.
  • ReactiveCocoaはイベントに多くの処理方法を提供し、RACを利用してイベントを処理するのが便利で、処理することと、傍受することのコードを一緒に置くことができ、これは非常に便利で、私たちが管理するのに便利で、対応する方法に飛び込む必要はありません.私たちが開発したの考えによく合っています.

  • 3.プログラミング思想
    開発では、あるフレームワークにあまり依存することはできません.そうしないと、このフレームワークが更新されず、プロジェクトの後期にメンテナンスができません.例えば、Facebookが提供したThree20 は、当時も神器でしたが、その後更新されず、誰も使っていませんでした.そのため、フレームワークを学ぶには、 を理解する必要があると思います. :開発の中で私たちはいろいろな需要に出会って、よくこれらの需要をどのように迅速に完成するかを考えて、このようにゆっくりとこれらの需要を迅速に完成する思想を形成します.
    まず、現在知られている を簡単に紹介します.
    3.1 :処理はプロセスを核心とし、一歩一歩実現する.
    3.2 :万物すべて対象
    3.3 :複数の操作(複数行コード)をポイント(.)に通すリンクは一緒に1つのコードになって、コードの可読性をよくします.a(1).b(2).c(3)
  • :メソッドの戻り値はblockであり、blockには戻り値(自身のオブジェクト)が必要であり、blockパラメータ(操作が必要な値)
  • が必要である.
  • :masonryフレームワーク.
  • :masonryを真似て、加算計算機を書いて、チェーンプログラミングの思想を練習します.

  • 3.4 :呼び出し順序を考慮する必要はなく、考慮結果を知るだけで、蝶効果に似ていて、1つのイベントが発生して、多くのものに影響して、これらのイベントは流れのように伝播して、それから結果に影響して、対象に向かう一言を借りて、万物はすべて流れています.
  • :KVO運用.
  • :KVO下地実装.

  • 3.5 :操作をできるだけ一連のネストされた関数またはメソッド呼び出しに書く.
  • :メソッドにBlockを入力し、メソッドにBlock呼び出しをネストし、コードを集約して
  • を管理する.
  • :メソッドごとに戻り値(自分のオブジェクト)が必要であり、関数またはBlockをパラメータとし、blockパラメータ(操作が必要な値)block戻り値(操作結果)
  • が必要である.
  • :ReactiveCocoa.
  • :関数式のプログラミングで実現する、加算器を1つ書き、加算器がある値に等しいか否かを判断する.

  • 4.ReactiveCocoaプログラミング思想
    ReactiveCocoaはいくつかのプログラミングスタイルを結合しています. (Functional Programming) (Reactive Programming)
    したがって、ReactiveCocoaが関数応答プログラミング(FRP)フレームワークとして記述されていると聞いたことがあるかもしれません.
    その後RACを用いて問題を解決すると,呼び出し順序を考慮する必要がなく,結果を直接考慮し,操作ごとに一連のネストされた方法に書き,コードを高集約し,管理を容易にする.
    5.ReactiveCocoaフレームワークのインポート方法
    通常、CocoaPods(サードパーティ製フレームワークを管理するプラグイン)を使用してインポートを支援します.
    PS:CocoaPodsチュートリアル(http://code4app.com/article/cocoapods-install-usage) :新しいプロジェクトを作成し、プレゼンテーションの下で、フレームワークのインポートを行います. :
  • podfile pod'ReactiveCocoa'のみを記述すると、'~>4.0となる.2-alpha-1'はインポートに失敗します
  • エラーメッセージ
  • podfileにuse_を追加する必要がありますframeworks、再pod installでインポートに成功します.

  • 6.ReactiveCocoa共通クラス.
    学習フレームワークの最も重要な点:個人はまずフレームワークでよく使われるクラスを明らかにしなければならないと思って、RACの中で最も核心的なクラスRACSiganlで、このクラスを完成してReactiveCocoaで開発することができます. :一般的なクラスの紹介RACSiganl:信号類は、一般的に将来データ伝達があることを示し、データが変化すれば、信号内部でデータを受信し、すぐにデータを送信する.
  • 信号クラス(RACSiganl)は、データが変更されると、信号内部からデータが送信され、それ自体が信号を送信する能力を備えず、内部のサブスクライバに渡されて送信されることを示す.
  • デフォルトの1つの信号はすべて冷たい信号で、つまり値が変わってもトリガーされません.この信号を購読してこそ、この信号は熱信号になり、値が変わってからトリガーされます.
  • 信号の購読方法:RACSignalのsubscribeNextを呼び出して購読できます.
  • RACSiganl :
  •     // RACSignal    :
        // 1.     + (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe
        // 2.    ,      . - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
        // 3.     - (void)sendNext:(id)value
    
    
        // RACSignal    :
        // 1.    ,   didSubscribe      ,     。
        // 2.      ,     signal subscribeNext:nextBlock
        // 2.2 subscribeNext        subscriber,   nextBlock   subscriber 。
        // 2.1 subscribeNext     siganl didSubscribe
        // 3.siganl didSubscribe   [subscriber sendNext:@1];
        // 3.1 sendNext        subscriber nextBlock
    
        // 1.    
        RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id subscriber) {
    
            // block    :          ,    block。
    
            // 2.    
            [subscriber sendNext:@1];
    
            //         ,        ,       [RACDisposable disposable]      。
            [subscriber sendCompleted];
    
            return [RACDisposable disposableWithBlock:^{
    
                // block    :             ,        block,      。
    
                //    Block ,           。
    
                NSLog(@"     ");
    
            }];
        }];
    
        // 3.    ,      .
        [siganl subscribeNext:^(id x) {
            // block    :         ,    block.
            NSLog(@"     :%@",x);
        }];
    
    
    RACSubscriber:サブスクライバの意味を表し、信号を送信するために使用されます.これはプロトコルであり、クラスではありません.このプロトコルを遵守し、方法を実現すればサブスクライバになります.createで作成された信号には、データの送信を支援するサブスクライバがいます.RACDisposable:リソースの購読またはクリーンアップをキャンセルするために使用され、信号の送信が完了したり、エラーが送信されたりすると、自動的にトリガーされます.
  • :ある信号を傍受したくない場合は、それによって購読信号をアクティブにキャンセルすることができます.
  • RACSubject:RACSubject:信号プロバイダは、自分が信号として機能し、信号を送信することができる.
  • :通常はエージェントの代わりに使用され、それがあればエージェントを定義する必要はありません.
  • RACReplaySubject:信号クラス、RACSubjectのサブクラスを繰り返し提供する.
  • RACReplaySubjectRACSubjectの違い:
  • RACReplaySubjectは先に信号を送信することができ、購読信号ではRACSubjectはできません.

  • :1つの信号が購読されるたびに、前の値を繰り返し送信し、繰り返し提供信号クラスを使用する必要があります.
  • :キャッシュされたvalueの数を制限するためにcapacityの数を設定できます.すなわち、最新の数の値のみをチャージします.
  • RACSubject RACReplaySubject :
  •     // RACSubject    
        // 1.     [RACSubject subject], RACSiganl   ,       block。
        // 2.     - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
        // 3.     sendNext:(id)value
    
        // RACSubject:     RACSignal   。
        // 1.  subscribeNext    ,          ,      nextBlock     。
        // 2.  sendNext    ,            ,          nextBlock。
    
        // 1.    
        RACSubject *subject = [RACSubject subject];
    
        // 2.    
        [subject subscribeNext:^(id x) {
            // block    :       ,    .
            NSLog(@"      %@",x);
        }];
        [subject subscribeNext:^(id x) {
            // block    :       ,    .
            NSLog(@"      %@",x);
        }];
    
        // 3.    
        [subject sendNext:@"1"];
    
    
        // RACReplaySubject    :
        // 1.     [RACSubject subject], RACSiganl   ,       block。
        // 2.       ,        。
        // 2.1      - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
        // 2.2      sendNext:(id)value
    
        // RACReplaySubject:     RACSubject   。
        // 1.  sendNext    ,      ,              ,          nextBlock。
        // 2.  subscribeNext    ,        ,          nextBlock
    
        //            ,          ,       ,     。
        //        ,    。
    
        // 1.    
        RACReplaySubject *replaySubject = [RACReplaySubject subject];
    
        // 2.    
        [replaySubject sendNext:@1];
        [replaySubject sendNext:@2];
    
        // 3.    
        [replaySubject subscribeNext:^(id x) {
    
            NSLog(@"            %@",x);
        }];
    
        //     
        [replaySubject subscribeNext:^(id x) {
    
            NSLog(@"            %@",x);
        }];
    
    
  • RACSubject
  •     //   :
        // 1.            ,modal         
        // 2.      view     ,    ,       
    
       :       .h,    RACSubject    。
    @interface TwoViewController : UIViewController
    
    @property (nonatomic, strong) RACSubject *delegateSignal;
    
    @end
    
       :            
    @implementation TwoViewController
    - (IBAction)notice:(id)sender {
        //         ,   ,     
    
         //     
         //           
        if (self.delegateSignal) {
            //   ,     
            [self.delegateSignal sendNext:nil];
        }
    }
    @end
    
       :        ,      ,              ,    .
    @implementation OneViewController
    - (IBAction)btnClick:(id)sender {
    
        //         
        TwoViewController *twoVc = [[TwoViewController alloc] init];
    
        //       
        twoVc.delegateSignal = [RACSubject subject];
    
        //       
        [twoVc.delegateSignal subscribeNext:^(id x) {
    
            NSLog(@"       ");
        }];
    
        //          
        [self presentViewController:twoVc animated:YES completion:nil];
    
    }
    @end
    
    
    RACTuple:ユニット類、NSArrayに類似し、値を包装する.RACSequence:NSArray,NSDictionaryの代わりにRACの集合クラスを使用して、配列や辞書をすばやく巡回できます. :1.ディクショナリモデルRACSequence RACTuple
        // 1.    
        NSArray *numbers = @[@1,@2,@3,@4];
    
        //        
        //    :         RACSequence numbers.rac_sequence
        //    :    RACSequence  RACSignal   ,numbers.rac_sequence.signal
        //    :     ,    ,           ,    。
        [numbers.rac_sequence.signal subscribeNext:^(id x) {
    
            NSLog(@"%@",x);
        }];
    
    
        // 2.    ,            RACTuple(    )
        NSDictionary *dict = @{@"name":@"xmg",@"age":@18};
        [dict.rac_sequence.signal subscribeNext:^(RACTuple *x) {
    
            //     ,      ,             
            RACTupleUnpack(NSString *key,NSString *value) = x;
    
            //        
    //        NSString *key = x[0];
    //        NSString *value = x[1];
    
            NSLog(@"%@ %@",key,value);
    
        }];
    
    
        // 3.     
        // 3.1 OC  
        NSString *filePath = [[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil];
    
        NSArray *dictArr = [NSArray arrayWithContentsOfFile:filePath];
    
        NSMutableArray *items = [NSMutableArray array];
    
        for (NSDictionary *dict in dictArr) {
            FlagItem *item = [FlagItem flagWithDict:dict];
            [items addObject:item];
        }
    
        // 3.2 RAC  
        NSString *filePath = [[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil];
    
        NSArray *dictArr = [NSArray arrayWithContentsOfFile:filePath];
    
        NSMutableArray *flags = [NSMutableArray array];
    
        _flags = flags;
    
        // rac_sequence   :  subscribeNext,       nextBlock,      。
        [dictArr.rac_sequence.signal subscribeNext:^(id x) {
            //   RAC    ,x:  
    
            FlagItem *item = [FlagItem flagWithDict:x];
    
            [flags addObject:item];
    
        }];
    
        NSLog(@"%@",  NSStringFromCGRect([UIScreen mainScreen].bounds));
    
    
        // 3.3 RAC    :
        NSString *filePath = [[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil];
    
        NSArray *dictArr = [NSArray arrayWithContentsOfFile:filePath];
        // map:     ,  :    value       
        // array:         
        //     :      ,          ,     ,          。
        NSArray *flags = [[dictArr.rac_sequence map:^id(id value) {
    
            return [FlagItem flagWithDict:value];
    
        }] array];
    
    
    RACMulticastConnection:1つの信号が複数回購読された場合、信号の作成を保証するために、複数回作成信号のblockを呼び出すことを回避し、副作用をもたらすために、このクラスの処理を使用することができる. :RACMulticastConnectionは、RACSignalの-publishまたは-muticast:メソッドによって作成する.RACMulticastConnection :
        // RACMulticastConnection    :
        // 1.     + (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe
        // 2.     RACMulticastConnection *connect = [signal publish];
        // 3.    ,  :           ,       。 [connect.signal subscribeNext:nextBlock]
        // 4.   [connect connect]
    
        // RACMulticastConnection    :
        // 1.  connect,connect.sourceSignal -> RACSignal(    )  connect.signal -> RACSubject
        // 2.  connect.signal,   RACSubject subscribeNext,     ,          ,    block。
        // 3.[connect connect]     RACSignal(    ),      RACSubject
        // 3.1.      ,          didSubscribe
        // 3.2 didSubscribe,       sendNext,     RACSubject sendNext
        // 4.RACSubject sendNext,   RACSubject         。
        // 4.1        ,     RACSubject,              ,     nextBlock
    
    
        //   :            ,            ,          。
        //   :  RACMulticastConnection    .
    
        // 1.      
       RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
    
    
            NSLog(@"    ");
    
            return nil;
        }];
        // 2.    
        [signal subscribeNext:^(id x) {
    
            NSLog(@"    ");
    
        }];
        // 2.    
        [signal subscribeNext:^(id x) {
    
            NSLog(@"    ");
    
        }];
    
        // 3.    ,         ,               
    
    
        // RACMulticastConnection:        
        // 1.    
        RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
    
    
            NSLog(@"    ");
            [subscriber sendNext:@1];
    
            return nil;
        }];
    
        // 2.    
        RACMulticastConnection *connect = [signal publish];
    
        // 3.    ,
        //   :    ,       ,          ,      ,     ,             sendNext:
        [connect.signal subscribeNext:^(id x) {
    
            NSLog(@"      ");
    
        }];
    
        [connect.signal subscribeNext:^(id x) {
    
            NSLog(@"      ");
    
        }];
    
        // 4.  ,    
        [connect connect];
    
    
    RACCommand:RACでイベントを処理するために使用されるクラスは、イベントをどのように処理するか、イベントのデータをどのように伝達するか、このクラスにパッケージすることができ、イベントの実行プロセスを簡単に監視することができます. :傍受ボタンクリック、ネットワーク要求RACCommand
    
        //  、RACCommand    :
        // 1.     initWithSignalBlock:(RACSignal * (^)(id input))signalBlock
        // 2. signalBlock ,  RACSignal,    signalBlock    
        // 3.     - (RACSignal *)execute:(id)input
    
        //  、RACCommand    :
        // 1.signalBlock         ,   nil.
        // 2.         ,        [RACSignal empty];
        // 3.RACCommand          ,    [subscriber sendCompleted],          ,         。
    
        //  、RACCommand    :  signalBlock          ,        。
        // 1. RAC   ,           RACCommand,      RACCommand      。
        // 2. RACCommand          ,             ,        signalBlock        。
    
        //  、    RACCommand          。
        // 1.RACCommand       executionSignals,   signal of signals(     ),             ,       。
        // 2.  executionSignals    RACCommand      ,    signalBlock     ,        。
    
        //  、            executing
    
        //  、    ,      ,    
    
    
        // 1.    
        RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
    
    
            NSLog(@"    ");
    
            //      ,      
            //        return [RACSignal empty];
    
            // 2.    ,      
            return [RACSignal createSignal:^RACDisposable *(id subscriber) {
    
                [subscriber sendNext:@"    "];
    
                //   :     ,    sendCompleted,         。
                [subscriber sendCompleted];
    
                return nil;
            }];
    
        }];
    
        //      ,     ,        
        _conmmand = command;
    
    
        // 3.    
        [self.conmmand execute:@1];
    
        // 4.  RACCommand    
        [command.executionSignals subscribeNext:^(id x) {
    
            [x subscribeNext:^(id x) {
    
                NSLog(@"%@",x);
            }];
    
        }];
    
        // RAC    
        // switchToLatest:  signal of signals,  signal of signals       ,         RACCommand    
        [command.executionSignals.switchToLatest subscribeNext:^(id x) {
    
            NSLog(@"%@",x);
        }];
    
        // 5.          ,      ,      ,skip         。
        [[command.executing skip:1] subscribeNext:^(id x) {
    
            if ([x boolValue] == YES) {
                //     
                NSLog(@"    ");
    
            }else{
                //     
                NSLog(@"    ");
            }
    
        }];
    
    
    RACScheduler:RACのキューは、GCDでカプセル化されています.RACUnit:表RACEvent:データをシグナルイベント(signal event)にパッケージします.それは主にRACSignalの-materializeによって使用され、卵を並べます.
    7.ReactiveCocoa開発でよく使われる使い方.
    7.1代替エージェント:
  • rac_signalForSelector:代替エージェントに使用されます.

  • 7.2 KVOの代わりに:
  • rac_valuesAndChangesForKeyPath:オブジェクトのプロパティの変更を監視します.

  • 7.3リスニングイベント:
  • rac_signalForControlEvents:イベントをリスニングするために使用されます.

  • 7.4代替通知:
  • rac_addObserverForName:通知を傍受するために使用されます.

  • 7.5テキストボックスのテキスト変更を傍受する:
  • rac_textSignal:テキストボックスが変更されると、この信号が送信されます.

  • 7.6処理インタフェースに複数の要求がある場合、すべてのデータを取得する必要がある場合、インタフェースを表示する
  • rac_liftSelector:withSignalsFromArray:Signals:受信されたSignals(信号配列)は、各signalが少なくともsendNextを1回通過すると、最初のselectorパラメータの方法をトリガする.
  • 使用注意:いくつかの信号、パラメータの1つの方法はいくつかのパラメータで、各パラメータは信号が発行したデータに対応します.

  • 7.7コードデモ
    
        // 1.    
        //   :   redView,    view     
        //             ,   View        ,       ,       
        // rac_signalForSelector:                  ,        ,      。
        //       redV  btnClick:,      ,     。
        [[redV rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) {
            NSLog(@"      ");
        }];
    
        // 2.KVO
        //    redV center         ,           
        // observer:    nil
        [[redV rac_valuesAndChangesForKeyPath:@"center" options:NSKeyValueObservingOptionNew observer:nil] subscribeNext:^(id x) {
    
            NSLog(@"%@",x);
    
        }];
    
        // 3.    
        //             ,    ,      
        [[self.btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
    
            NSLog(@"      ");
        }];
    
        // 4.    
        //            
        [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
            NSLog(@"    ");
        }];
    
        // 5.          
       [_textField.rac_textSignal subscribeNext:^(id x) {
    
           NSLog(@"     %@",x);
       }];
    
       // 6.      ,        ,     .
        RACSignal *request1 = [RACSignal createSignal:^RACDisposable *(id subscriber) {
    
            //     1
            [subscriber sendNext:@"    1"];
            return nil;
        }];
    
        RACSignal *request2 = [RACSignal createSignal:^RACDisposable *(id subscriber) {
            //     2
            [subscriber sendNext:@"    2"];
            return nil;
        }];
    
        //     :    ,           ,             。
        [self rac_liftSelector:@selector(updateUIWithR1:r2:) withSignalsFromArray:@[request1,request2]];
    
    
    }
    //   UI
    - (void)updateUIWithR1:(id)data r2:(id)data1
    {
        NSLog(@"  UI%@  %@",data,data1);
    }
    
    

    8.ReactiveCocoa共通マクロ.
    8.1 RAC(TARGET, [KEYPATH, [NIL_VALUE]]):オブジェクトに対する属性バインド.
        //          ,    label   
        RAC(self.labelView,text) = _textField.rac_textSignal;
    
    

    8.2 RACObserve(self, name):オブジェクトのプロパティをリスニングし、信号を返します.
    [RACObserve(self.view, center) subscribeNext:^(id x) {
    
            NSLog(@"%@",x);
        }];
    
    

    8.3 @weakify(Obj) @strongify(Obj)、一般的に両方とも組み合わせて使用し、循環引用問題を解決する.
    8.4 RACTuplePack:データをRACTuple(タプル類)に包装する
        //             
        RACTuple *tuple = RACTuplePack(@10,@20);
    

    8.5 RACTupleUnpack:RACTuple(タプルクラス)を対応するデータに解包する.
        //             
        RACTuple *tuple = RACTuplePack(@"xmg",@20);
    
        //     ,      ,             
        // name = @"xmg" age = @20
        RACTupleUnpack(NSString *name,NSNumber *age) = tuple;