錯(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),RACSignal的subscribeNext的實(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;
}