获取一个 NSArray
Posted
技术标签:
【中文标题】获取一个 NSArray【英文标题】:Get one NSArray 【发布时间】:2014-05-21 23:37:16 【问题描述】:我想知道如何将两个array
合并为一个array
。
我希望组合的 tableView
显示最新的。
如有必要,我会发布任何额外的代码或帮助,非常感谢!
【问题讨论】:
iArray
和 hArray
的内容是否属于 seme 类型(我的意思是它们有 Feed
对象)?是否需要将iArray
的内容放在最前面,然后将hArray
的内容按顺序排列?否则,您可以使用NSMutableArray
,在其中使用arrayByAddingObjectsFromArray:
,或者在对象上手动使用(一个简单的for循环就足够了)。
@Reez 我在你的代码中发现了这个错误,在 tableview:cellForRowAtIndexpath 方法的 else 部分 // API 2 Data *dataLocal = [iArray objectAtIndex:indexPath.row - headingsArray.count];在这里,你应该使用 hArray.count 而不是 headersArray.count
嘿,我修好了,谢谢提醒
【参考方案1】:
在您的 UITableViewDataSource 方法中,组合两个数组并相应地使用一个或另一个:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
// API1 + API2
return hArray.count + iArray.count;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
UITableViewCell *cell;
if(indexPath.row < hArray.count)
// API 1
YourAPI1Cell *api1Cell = [tableView dequeueReusableCellWithIdentifier:@"YourAPI1Cell"];
// Do everything you need to do with the api1Cell
// Use the index in 'indexPath.row' to get the object from you array
cell = api1Cell;
else
// API 2
YourAPI2Cell *api2Cell = [tableView dequeueReusableCellWithIdentifier:@"YourAPI2Cell"];
// Do everything you need to do with the api2Cell
// Remember to use 'indexPath.row - hArray.count' as the index for getting an object for your second array
cell = api2Cell;
return cell;
【讨论】:
@Wain 根据我在问题中的上述评论,我试图让它像一个时间线,所以这就是为什么我不想在表格中制作不同的部分,如果这就是你的意思。还是你的意思是别的? 当我滚动大约 20 个单元格时出现崩溃“由于未捕获的异常 NSRangeException 导致应用程序终止,原因:[__NSArrayM objectAtIndex:]:索引 20 超出范围 [0 .. 19]” 而tableView
在前 10 个tableViewCell
s 中使用API1
,在接下来的 20 个tableViewCell
s 中使用API2
,然后崩溃。有任何想法吗?谢谢!
我根据您的代码重新配置,然后还去情节提要添加了第二个原型单元格和标识符,并尝试了一下,这就是我遇到上一个崩溃/错误的地方。
在控制台中,API1
有10 objects
,API2
有20 objects
。所以我无法判断它是否只是在加载任何 API2
对象之前加载所有 API1
对象而不考虑日期。【参考方案2】:
我想您的实际代码有效。这些是您可以执行的步骤。我没有尝试(不知道它是否编译),但你会明白整个想法。
• 我会选择:
@property (nonatomic, strong) NSMutableArray *contentArray;
在进行 WebService 请求之前不要忘记初始化它:contentsArray = [[NSMutableArray alloc] init];
。
• 在积木中,我会做:
[contentsArray addObjectsFromArray:mappingResult.array];
• 您需要按日期对它们进行排序,所以由于我们只需要添加一个方法对它们进行排序,但我不知道Feed
和Data
([mappingResult array]
中的对象)如何,我会让你做的。但我给你主要的想法,因为在@Wain 的答案的cmets 中,你说日期是NSString
。
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
//Do the dateFormatter settings, you may have to use 2 NSDateFormatters if the format is different for Data & Feed
//The initialization of the dateFormatter is done before the block, because its alloc/init take some time, and you may have to declare it with "__block"
//Since in your edit you do that and it seems it's the same format, just do @property (nonatomic, strong) NSDateFormatter dateFormatter;
NSArray *sortedArray = [contentsArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b)
NSDate *aDate, bDate;
if ([a isKindOfClass:[Feed class]])
aDate = [dateFormatter dateFromString:(Feed *)a.created_time];
else //if ([a isKindOfClass:[Data class]])
aDate = [dateFormatter dateFromString:(Data *)a.published];
if ([b isKindOfClass:[Feed class]])
bDate = [dateFormatter dateFromString:(Feed *)b.created_time];
else //if ([b isKindOfClass:[Data class]])
bDate = [dateFormatter dateFromString:(Data *)b.published];
return [aDate compare:bDate];
];
• 在数据源方法tableView:numberOfRowsInSection
中,执行return [contentsArray count];
• 在数据源方法tableView:cellForRowAtIndexPath:
if ([[[contentsArray objectAtIndexPath:[indexPath row]] isKindOfClass:[Feed class]])
Feed *feed = [contentsArray objectAtIndexPath:[indexPath row]];
CellClassFeed *cell = [tableView dequeueReusableCellWithIdentifier:@"APICell1"];
//Do your thing
else //if ([[[contentsArray objectAtIndexPath:[indexPath row]] isKindOfClass:[Data class]])
Data *data = [contentsArray objectAtIndexPath:[indexPath row]];
CellClassData *cell = [tableView dequeueReusableCellWithIdentifier:@"APICell2"];
//Do your thing
【讨论】:
Feed
和 Data
的 .h,尤其是显示要排序的属性应该是个好主意。另一个问题是:Feed 和 Data 有那么大的不同吗?你不能把他们重新组合到一个班级里吗?
我添加了一种排序方式,或者至少是它背后的主要思想。
哪一行导致错误?您复制了我的代码,但我建议您执行 @property (nonatomic, strong) NSDateFormatter *dateFormatter;
您在请求 WebService 数据之前执行初始化并设置日期格式。你可能不得不在你之前的NSDateFormatter
中评论tableView:cellForRowAtIndexPath:
中的行,因为它们变得无用了。并且要小心。由于我只是给出了主要想法,所以你排序是在sortedArray
而不是你的contentsArray
。
否则,问题可能是aDate = [dateFormatter dateFromString:(Feed *)a.published];
,您可能需要将其替换为:Feed *feedObject = (Feed *)a; aDate = [dateFormatter dateFromString:feedObject.published];` (ans 对其余的 if
测试执行相同的逻辑。另外,由于 Feed
和 Data
` 看起来完全不同,这可能不是一个好主意正如我之前在一节课上建议的那样“重新组合他们”。
我通过添加一些花括号,然后使用feedObject.published
和dataObject.created_time
想出了一些事情,所以我没有收到错误。但是在它运行之前的两个问题是,我在每个 aDate = [dateFormatter1 dateFromString:feedObject.published];
行旁边收到警告说 Incompatible pointer types sending NSDate to parameter of type NSString
?然后sortedArray
在您的代码中未使用,所以我也不知道该怎么处理?【参考方案3】:
我会为表格数据保留一个属性:
@property (strong, nonatomic) NSMutableArray *tableDataList;
并有一个在每个成功块中调用的方法:
- (void)addTableData:(NSArray *)items
[self.tableDataList addObjectsFromArray:items];
[self.tableDataList sortUsingDescriptors:...];
[self.tableView reloadData];
您传递mappingResult.array
并填写排序描述符信息以获取您的时间线排序。
那么你的表视图委托/数据源方法真的很简单,只需参考self.tableDataList
。
这与@Larme 的答案比较相似。从这里我会得到项目并检查类来决定如何配置单元:
id item = [self.tableDataList objectAtIndex:indexPath.row];
if ([item isKindOfClass:[Feed class]])
Feed *feed = (Feed *)item;
... // configure the feed cell
else
Data *data = (Data *)item;
... // configure the data cell
【讨论】:
不应该是id item = [self.tableDataList objectAtIndexPath:yyy];
吗?
应该的,我的属性名和方法名错误,谢谢@Larme
到目前为止,我已经添加了tableDataList
属性,添加了addTableData
方法,但是我应该根据您在我的代码中看到的方法在该方法内部对日期进行排序吗?我从来没有使用过这些,现在正试图找到一些关于它的信息,但看不到任何让我印象深刻的东西。如果可以,请提供帮助,谢谢 Wain!
排序描述符将使用published
或created_time
,但Feed
和Data
类都需要有一个返回NSDate
的通用方法,以便您可以一致地对所有内容进行排序
比较器排序将起作用,但我会修改数据类以返回通用日期格式,以便可以使用排序描述符并且代码会更清晰。那么是的,我的代码用于单元配置。【参考方案4】:
这个问题复杂的原因是数据异步来自两个不同的来源。抓住这一点,我们已经控制住了问题。我的建议与其他建议不同,它旨在立即处理多个异步源,在所有其他区域留下更简单的代码。
处理两个异步源的方法是使用嵌套完成对它们进行序列化。在这里,我只是将您发布的代码分解为两种方法,一种用于每个 api。每个都需要一个匹配对象管理器接口的成功和失败块...
- (void)loadOneWithSuccess:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success
failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure
NSString *apikey = @kCLIENTKEY;
NSDictionary *queryParams = @@"apikey" : apikey;
NSString *path = [NSString stringWithFormat:@"v1/n/?limit=4&leafs=%@&themes=%@", leafAbbreviation, themeID];
[self.eObjectManager getObjectsAtPath:path parameters:queryParams success:success failure:failure];
- (void)loadTwoWithSuccess:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success
failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure
NSString *path = @"v1/u/2/m/recent/?client_id=e999";
[self.iObjectManager getObjectsAtPath:path parameters:nil success:success failure:failure];
现在我们可以让 loadMedia 做我们需要的事情,即从每个 api 加载、组合和排序为单个模型。声明一个名为 combinedModel
的 NSMutableArray
属性。其他答案建议将此作为 tableDataList 或 contentArray。我的建议的主要区别是将组合作为组合提取的一部分来处理。
- (void)loadMedia
self.combinedModel = [NSMutableArray array];
[self loadOneWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
[self.combinedModel addObjectsFromArray:mappingResult];
// here's the trick. call API2 here. Doing so will serialize these two requests
[self loadTwoWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
[self.combinedModel addObjectsFromArray:mappingResult];
[self sortCombinedModel];
[self.tableView reloadData];
failure:^(RKObjectRequestOperation *operation, NSError *error)
NSLog(@"No?: %@", error);
];
failure:^(RKObjectRequestOperation *operation, NSError *error)
NSLog(@"No?: %@", error);
];
现在只剩下两个问题(1)对异构对象数组进行排序,(2)在表格视图中渲染异构对象。第一类:
- (void)sortCombinedModel
[self.combinedModel sortUsingComparator:^NSComparisonResult(id a, id b)
NSDate *dateA, *dateB;
dateA = ([a isKindOfClass:[Feed self]])? ((Feed *)a).published : ((Data *)a).created_time;
dateB = ([b isKindOfClass:[Feed self]])? ((Feed *)b).published : ((Data *)b).created_time;
return [dateA compare:dateB];
];
现在对于表格,self.combinedModel
是表格视图的新模型。所有数据源方法都应该引用它。 cellForRowAtIndexPath: 的行为应该和 sort: 一样。简而言之……
id model = self.combinedModel[indexPath.row];
if ([model isKindOfClass:[Feed self])
Feed *feed = (Feed *)model;
// configure cell with feed
else
Data *data = (Data *)model;
// configure cell with data
【讨论】:
首先,感谢您提供如此出色+具体+详细的答案。快速提问,我在哪里使用sortedArray
?是在// configure cell with feed/data
部分下,还是在其他地方?
如果是这样,我需要为它创建一个属性吗?
那是我的错。我认为您可以/应该用排序数组替换模型。请看编辑。现在 sort 方法将排序后的数组分配给 combineModel。
我看到的唯一问题是我在self.combinedModel = [self.combinedModel sortedArrayUsingComparator:^NSComparisonResult(id a, id b) NSDate *dateA, *dateB;
上收到警告说“从 NSArray 分配给 NSMutableArray 的指针类型不兼容。”如果我尝试将combinedModel
更改为NSArray
,那么我在loadMedia
方法中会出现2 个错误。我该怎么办?
哦,再次抱歉。请将该属性保留为可变并查看我的编辑。可变数组有它自己的破坏性排序方法。另外,请记住在您的数据源方法中仅引用该组合数组,例如像 numberOfRowsInSection 应该回答 combineModel.count。以上是关于获取一个 NSArray的主要内容,如果未能解决你的问题,请参考以下文章