Reputation: 532
Is there a way for me to populate one UITableView
with two separate web APIs? I'm sure there is, but I can't quite figure it out.
Currently I'm pulling perfectly from one web API; but I need to pull from a different one and then merge them into one UITableView
.
(I'm using RestKit)
(Second API I'm trying to integrate is Instagram, and will pull pictures/text from a user account)
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// RestKit
NSString *baseURL = @"http://api.firstwebsite.com/v1";
RKObjectManager *manager = [RKObjectManager sharedManager];
if (!manager) {
manager = [RKObjectManager objectManagerWithBaseURLString:baseURL];
manager.client.serviceUnavailableAlertEnabled = YES;
manager.requestQueue.showsNetworkActivityIndicatorWhenBusy = YES;
} else {
manager.client.baseURL = [RKURL URLWithString:baseURL];
}
return YES;
}
WebListViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:
[NSString stringWithFormat:
@"/something/?limit=100&something=%@&something=%@&apikey=xxxx", var1, var2]
usingBlock:^(RKObjectLoader *loader) {
loader.onDidLoadObjects = ^(NSArray *objects){
hArray = objects;
[_tableView reloadData];
};
[loader.mappingProvider setMapping:[Fe mapping] forKeyPath:@"fe"];
loader.onDidLoadResponse = ^(RKResponse *response){
//NSLog(@"BodyAsString: %@", [response bodyAsString]);
};
}];
}
I'm assuming I'll need to do something different in the AppDelegate.m
with the baseURL
since it will have two different base URLs.
Will post any extra code as needed!
EDIT
Per alexandresoli answer here's what I've updated so far, but still need help on:
WebListViewController.m
@property (strong, nonatomic) NSMutableArray *array;
@synthesize array;
- (void)callBothURLs {
// Call both #1 and #2 URL, not sure what specific code goes here
}
- (void)viewDidLoad {
[self callBothURLs];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// This is what I currently have, was pulling from a `Headlines` `NSArray` from web #1
return headlinesArray.count;
// I believe I need to change it to this next line...
//return array.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Not sure what to put here with the new `NSMutableArray`
}
EDIT 2
I already have my object mapping set up for the first website, so I can easily do that part for the Instagram API. All my confusion/problems seem to be in the WebListViewController. Anyway here is a sample of mapping.
Mapping.h
@interface Mapping : NSObject
@property (nonatomic, strong) Links *links;
@property (nonatomic, strong) NSString *headline;
@property (nonatomic, strong) NSArray *images;
+ (RKObjectMapping *) mapping;
@end
Mapping.m
@implementation Mapping
+ (RKObjectMapping *)mapping {
RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[self class] usingBlock:^(RKObjectMapping *mapping) {
[mapping mapKeyPathsToAttributes:
@"headline", @"headline",
nil];
[mapping hasMany:@"images" withMapping:[Images mapping]];
}];
return objectMapping;
}
@end
Upvotes: 0
Views: 1067
Reputation: 10323
Almost A to Z explanation.
Assumptions
Basic idea
Use NSMutableArray
to store result items. Start both API requests simultaneously and add result items into array in appropriate success blocks. When both API calls are finished, sort array and reload table.
Performing API calls
Perform API calls in your view controller (probably in viewDidLoad
), not in AppDelegate
. The basic example of RestKit object request can be found at github page. Let's name our API calls callAPI1
, callAPI2
. For example, [self callAPI1]
has following steps:
Try to use single class for result objects (you'll need to use different mappings for each API) to simplify sorting. [see below]
Respond to API calls
Now we need to know when both requests will finish, in order to reload table. Use a simple counter, which initially set to number of requests and decrements when each API call finishes.
Your method implementation might look like this:
@implementation ViewController
{
NSMutableArray *_items;
NSInteger _numberOfPendingCalls;
}
- (void)loadItems
{
_numberOfPendingCalls = 2;
[_items removeAllObjects];
[self callAPI1];
[self callAPI2];
}
In success block we decrement pending calls, add items and check for completion:
^(RKObjectRequestOperation *operation, RKMappingResult *result) {
_numberOfPendingCalls--;
[_items addObjectsFromArray:result.array];
if (_numberOfPendingCalls == 0) {
[self sortAndDisplayItems];
}
}
If mutable array contains instances of single class (or at least items have same property), you could use NSSortDescriptor
for sorting:
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
[_items sortUsingDescriptors:@[sortDescriptor]];
Where name
is a property of your result object.
I've omitted table view delegate implementation because it is straightforward.
Further steps
If you want to use RestKit object manager and your API have different base URLs, you need to use multiple object managers, one for each API. Reference: More than one RKObjectManager at a time (RestKit)
Upvotes: 1
Reputation: 928
Create a method that calls both urls and store the result for each url inside the same NSMutableArray using the method addObject.
NSMutableArray *array = [NSMutableArray new];
// for each object from URL 1, call [array addObject:object];
// for each object from URL 2, call [array addObject:object];
Use this array as the datasource for your tableview;
Update as requested:
Update 2:
- (void)viewDidLoad
{
[super viewDidLoad];
_array = [NSMutableArray new];
// fetch data from url 1
NSArray *arrayUrl1 = [self fetchUrl1];
// add url1 data to array
for (NSString *str in arrayUrl1) {
[_array addObject:str];
}
// fetch data from url 2
NSArray *arrayUrl2 = [self fetchUrl2];
// add url2 data to array
for (NSString *str in arrayUrl2) {
[_array addObject:str];
}
}
- (NSArray *)fetchUrl1
{
return [NSArray array];
}
- (NSArray *)fetchUrl2
{
return [NSArray array];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// total number of objects in array
return [_array count];
}
Upvotes: 1