gpt4 book ai didi

reactive-cocoa - 如何使用 RACCommands 处理表数据请求

转载 作者:行者123 更新时间:2023-12-01 02:18:27 24 4
gpt4 key购买 nike

我有一个用于保存数据元素数组的 UITableView 的 ViewModel。 UITableView 实现了下拉刷新和无限滚动行为。数据元素是通过 RestKit 从服务器以分页方式请求的,这意味着我必须以某种方式跟踪当前页面。我创建了 2 个单独的 RACCommands 来区分刷新和无限滚动加载,其中刷新总是加载第 0 页。整个过程有效,但我不喜欢它,想知道是否有更好的方法来做到这一点。另外,现在这 2 个命令可能会同时执行,这不是预期的。

@interface TableDataViewModel ()

@property(nonatomic, readonly) RestApiConnector *rest;
@property(nonatomic) int page;
@property(nonatomic) NSMutableArray *data;
@property(nonatomic) RACCommand *loadCommand;
@property(nonatomic) RACCommand *reloadCommand;

@end

@implementation TableDataViewModel

objection_requires_sel(@selector(rest))

- (id)init {
self = [super init];
if (self) {
[self configureLoadCommands];
[self configureActiveSignal];
}
return self;
}

- (void)configureActiveSignal {
[self.didBecomeActiveSignal subscribeNext:^(id x) {
if (!self.data) {
[self.reloadCommand execute:self];
}
}];
}

- (void)configureLoadCommands {
self.loadCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
return [self.rest dataSignalWithPage:self.page];
}];
self.reloadCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
return [self.rest dataSignalWithPage:self.page];
}];
self.loadCommand.allowsConcurrentExecution = FALSE;
self.reloadCommand.allowsConcurrentExecution = FALSE;

[self.reloadCommand.executionSignals subscribeNext:^(id x) {
RAC(self, data) = [x map:^id(id value) {
self.page = 0;
return [value mutableCopy];
}];
}];

[self.loadCommand.executionSignals subscribeNext:^(id x) {
RAC(self, data) = [x map:^id(id value) {
self.page++;
if (self.data) {
NSMutableArray *array = [self.data mutableCopy];
[array addObjectsFromArray:value];
return array;
} else {
return [value mutableCopy];
}
}];
}];
}
@end

我刚开始使用 ReactiveCocoa,所以我很感激任何其他提示。

谢谢!

最佳答案

I just started using ReactiveCocoa, so I'd appreciate any other tips for this.



如果您只想一次执行一个或另一个命令,实现此目的的一种方法是只使用一个命令(并禁用并发执行,正如您已经完成的那样):
1  const NSUInteger kLoad   = 0;
2 const NSUInteger kReload = 1;
3
4 - (void)configureActiveSignal {
5 @weakify(self);
6 RACSignal *dba = [[self.didBecomeActiveSignal filter:^(id _) {
7 @strongify(self);
8 return self.data;
9 }]
10 mapReplace:@( kReload )];
11
12 RACSignal *ls = [self.command rac_liftSelector:@selector(execute:) withSignals:dba];
13 [[ls publish] connect];
14 }
15
16 - (void)configureCommand {
17 @weakify(self);
18 self.command = [[RACCommand alloc] initWithSignalBlock:^(NSNumber *loadOrReload) {
19 @strongify(self);
20 return RACTuplePack(loadOrReload, [self.rest dataSignalWithPage:self.page]);
21 }];
22
23 RAC(self, page) = [self.command.executionSignals reduceEach:^(NSNumber *loadOrReload, id _) {
24 @strongify(self);
25 return kReload == loadOrReload.integerValue ? @0 : @( ++self.page );
26 }];
27 RAC(self, data) = self.command.executionSignals reduceEach:^(NSNumber *loadOrReload, NSArray *data) {
28 @strongify(self);
29 if (kReload == loadOrReload.integerValue)
30 {
31 return [data mutableCopy];
32 }
33 else
34 {
35 NSMutableArray *ma = [self.data mutableCopy];
36 [ma addObjectsFromArray:data]
37 return ma;
38 }
39 }];
40
41 self.command.allowsConcurrentExecution = NO;

注意,这是完全未经测试的。但我希望它传达了基本思想。
  • 可以从代码中推断出现在只有一个命令,其实例变量名为 command 。现在不再使用数据数组调用它,而是使用一个常量调用它来指示它是应该加载还是重新加载,您可以在第 18 行看到。
  • 第 5 行: 您的代码有很多保留周期。您不能从 self 强烈引用的块中(直接或通过对象所有权的间接链)强烈引用 self。 ReactiveCocoa 附带了 @strongify/weakify 宏来帮助减少这个难度。如您所见,任何时候您需要在命令拥有的块中引用 self(它本身由 self 拥有,因此循环),您需要创建对 self 的弱引用,然后在块内使用它.您在块内使用 @strongify 以避免与 ARC 的释放机制发生数据竞争。
  • 第 6 行: 使用 didBecomeActive 参数将 self.command 通知转换为 kReload 的执行(这会替换旧的 reloadCommand ),但前提是 self.data != nil ,使用 -filter:
  • 第 12 行: 这里是您实际调用 [self.command execute:] 的地方,但您可以通过将选择器提升到上面刚刚创建的信号上来实现。大概你有一些其他未显示的代码用于执行 self.loadCommand ,你需要调整它以传递 @( kLoad )
  • 第 13 行: -publish/connect 习惯用法通常用于当您想订阅信号而不实际对其值进行任何操作时。这在 RAC 2.x 中并不是绝对必要的。
  • 第 18 行: 您可以看到该命令现在将使用 NSNumber 调用其信号块,即您在第 6 行创建的信号上提升的常量。但是,在该命令之前,该命令仅返回数据,它现在返回一个包含 -execute: 输入和数据的元组。这是因为正如您将在下面看到的,下游操作需要访问这两条信息。
  • 第 23 行: 不再在信号订阅块(它几乎总是反模式)中使用 RAC() 宏,而是直接在 -configureCommand 方法中使用它。这里我们说的是,无论何时执行命令,都将 self.page 设置为 0++self.page ,具体取决于命令是使用 kLoad 还是 kReload 执行的。 -reduceEach: 操作只是为了方便解构通过信号发送的元组,这里我们只关心常量。 注意在这个 self.page 操作中增加 -reduceEach: 的副作用。 在信号操作中产生副作用通常是不好的形式。危险在于,如果 RAC(self, page) 以外的其他东西订阅了返回的信号,则实例变量的递增次数可能会超出您的预期。如果您能以某种方式从数据源获取 self.page 的值,而不是在全局实例变量中跟踪它,那将是理想的。
  • 第 27 行: 这只是您在第 23 行所做的事情的一个变体,但不是设置 self.page ,而是设置 self.data 。这次 -reduceEach: 操作确实需要使用元组中的第二个值(数据),该值被适本地转换为 kLoadkReload ,然后最终设置在 ivar 上。
  • 关于reactive-cocoa - 如何使用 RACCommands 处理表数据请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22539255/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com