在使用ReactiveCocoa時(shí),UITableViewCell里UIButton點(diǎn)擊事件的一種錯(cuò)誤實(shí)現(xiàn)

錯(cuò)誤實(shí)現(xiàn)方法

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *cellID = @"DSTestTableViewCell";
    DSTestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    if (!cell) {
        cell = [[DSTestTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
    }
    
    [[mcell.testBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
        NSLog(@"click action");
    }];
    return cell;   
}

上面這種方法,當(dāng)有多條數(shù)據(jù)時(shí)、或刷新頁面后,點(diǎn)擊button會(huì)掉用很多次點(diǎn)擊事件。
由于數(shù)據(jù)過多,或者刷新頁面時(shí),會(huì)啟用UITableView的復(fù)用機(jī)制,點(diǎn)擊事件會(huì)多次被注冊。

ReactiveCocoa注冊代碼如下:

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
    NSCParameterAssert(nextBlock != NULL);
    
    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
    return [self subscribe:o];
}
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCParameterAssert(subscriber != nil);

    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
    subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];

    NSMutableArray *subscribers = self.subscribers;
    @synchronized (subscribers) {
        [subscribers addObject:subscriber];
    }
    
    return [RACDisposable disposableWithBlock:^{
        @synchronized (subscribers) {
            // Since newer subscribers are generally shorter-lived, search
            // starting from the end of the list.
            NSUInteger index = [subscribers indexOfObjectWithOptions:NSEnumerationReverse passingTest:^ BOOL (id<RACSubscriber> obj, NSUInteger index, BOOL *stop) {
                return obj == subscriber;
            }];

            if (index != NSNotFound) [subscribers removeObjectAtIndex:index];
        }
    }];
}

查看ReactiveCocoa代碼可以發(fā)現(xiàn),RACSignalsubscribeNext的實(shí)現(xiàn)是一種訂閱者模式,每次注冊都會(huì)添加一個(gè)訂閱者信號量[subscribers addObject:subscriber];,一但觸發(fā)點(diǎn)擊事件,所有訂閱者的信號量都會(huì)被觸發(fā),從而觸發(fā)多次點(diǎn)擊事件。

解決的辦法就是避免多次注冊點(diǎn)擊事件

正確的實(shí)現(xiàn)方法

方法一
將注冊點(diǎn)擊事件,放到初始化cell中。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *cellID = @"DSTestTableViewCell";
    DSTestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    if (!cell) {
        cell = [[DSTestTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
        [[mcell.testBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
            NSLog(@"click action");
        }];
    }
    return cell;   
}

方法二
UITableViewCell中定義block,實(shí)現(xiàn)UIButton點(diǎn)擊事件,通過block傳遞事件。

[[_testBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
    if (self.controlClickBlock) {
        self.controlClickBlock
    }
}];

在UITableViewCell初始化時(shí),實(shí)現(xiàn)block。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *cellID = @"DSTestTableViewCell";
    DSTestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    if (!cell) {
        cell = [[DSTestTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
    }

    mcell.controlClickBlock = ^() {
        NSLog(@"click action");
    };
    return cell;   
}

方法三
使用rac_command實(shí)現(xiàn)點(diǎn)擊事件。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *cellID = @"DSTestTableViewCell";
    DSTestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    if (!cell) {
        cell = [[DSTestTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
    }

    @weakify(self)
    mcell.testBtn.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        @strongify(self)
        NSLog(@"click action");
        return [RACSignal empty];
    }];
    return cell;   
}

方法四(推薦)

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *cellID = @"DSTestTableViewCell";
    DSTestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    if (!cell) {
        cell = [[DSTestTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
    }
    
    [[[mcell.testBtn rac_signalForControlEvents:UIControlEventTouchUpInside] takeUntil:mcell.rac_prepareForReuseSignal] subscribeNext:^(id x) {
        NSLog(@"click action");
    }];
    return cell;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容