NSRangeException while deleting UICollectionView cells - objective-c

I'm trying to remove cells from UICollectionView in for.. in loop and every time I get NSRangeException. I can't understand why does it happen because firstly I sort my array and then trying to remove. So the problem is that I firstly try to send request to the server and only if response is succes my UICollectionView cells and array elements are removes. Here is my code:
Pass elements through the loop:
- (IBAction)deletePictures:(id)sender {
int i = 0;
if (selectedPhotosURL.count>0){
loadCount = (int)selectedPhotosURL.count;
//sorting an array (it works fine)
NSArray *indexPaths = sortMediaCollection.indexPathsForSelectedItems;
NSMutableArray *pathes = [NSMutableArray arrayWithArray:indexPaths];
NSSortDescriptor *highestToLowest = [NSSortDescriptor sortDescriptorWithKey:#"self" ascending:NO];
[pathes sortUsingDescriptors:[NSArray arrayWithObject:highestToLowest]];
[selecedCellsArray sortUsingComparator:^NSComparisonResult(NSString *str1, NSString *str2) {
return [str2 compare:str1 options:(NSNumericSearch)];
}];
NSLog(#"selectedCElls %#",selecedCellsArray);
for(NSIndexPath *indexPath in pathes) {
NSLog(#"indexPath in pathes is %ld",(long)indexPath.row);
AVMSMCell *cell = (AVMSMCell *)[sortMediaCollection cellForItemAtIndexPath:indexPath];
AVMDataStore *oneItem = [smArray objectAtIndex:indexPath.row];
NSString *contentId = oneItem.fileId;
if (i<selectedPhotosURL.count){
NSLog(#"indexPath second loop is %ld",(long)indexPath.row);
[self deleteUserPhotos:contentId : indexPath.row : cell]; // send request to the server it's ok too.
i++;
}
}
} else {
[self selectAtLeastOneFirst];
}
}
For example here I select 6 cells and my array sort with right order from up to down (5,4,3,2,1,0). Then I pass this elements in method with this order.
Request send method:
-(void)deleteUserPhotos : (NSString *)contentId : (NSInteger )pathRow : (AVMSMCell *) cell{
NSNumber *rowNsNum = [NSNumber numberWithUnsignedInt:(unsigned int)pathRow];
if (([selecedCellsArray containsObject:[NSString stringWithFormat:#"%#",rowNsNum]]) )
{
cell.selectedBG.backgroundColor = DANGER;
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSString *token = [defaults objectForKey:#"token"];
NSString *header = [NSString stringWithFormat:#"Bearer %#",token];
NSDictionary *params = #{#"lang": #"en",#"content_id":contentId,#"project_id":[defaults objectForKey:#"project_id"]};
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager.requestSerializer setValue:header forHTTPHeaderField:#"Authorization"];
[manager POST:#"http://example.com/api/project/delete-content" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"JSON: %#", responseObject);
if ([[responseObject objectForKey:#"result"] isEqualToString:#"success"]){
#try{
NSLog(#"pathRow in TRY %ld",(long)pathRow); // HERE I get wrong number after two or three elements already passed
[smArray removeObjectAtIndex:(unsigned int)pathRow];
[selecedCellsArray removeObject:[NSString stringWithFormat:#"%ld",(long)pathRow]];
cell.selectedBG.hidden = YES;
[sortMediaCollection reloadSections:[NSIndexSet indexSetWithIndex:0]];
loadCount--;
}
} #catch (NSException *e){
NSLog(#"something is bad %#",e);
[SVProgressHUD dismiss];
if (smArray.count<pathRow-1){
[smArray removeObjectAtIndex:(unsigned int)pathRow-1];
}
} #finally {
cell.selectedBG.hidden = YES;
[sortMediaCollection reloadSections:[NSIndexSet indexSetWithIndex:0]];
}
} else {
NSLog(#"can't delete photo!");
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"Error: %#", error);
errorEndSpinner
}];
}
}
So in method above I get wrong element number after two or three elements already passed i.e frist element is 5,then 4, then 2, 3,1,0.
And at this moment my #catch handle exception and trying to remove element with [smArray removeObjectAtIndex:(unsigned int)pathRow-1]; and then I get NSRangeException and my app crashing. What I do wrong?

I solved my problem with this answer and little bit modified my code.
I've got an NSRangeException because I removed my UICollectionView items through the loop. Instead I should better use multiple deleting instantly like this:
// Delete the items from the data source.
[self deleteItemsFromDataSourceAtIndexPaths:selectedItemsIndexPaths];
// Now delete the items from the collection view.
[sortMediaCollection deleteItemsAtIndexPaths:selectedItemsIndexPaths];
So now my code looks like:
Pass through the loop:
- (IBAction)deletePictures:(id)sender {
int i = 0;
if (selectedPhotosURL.count>0){
[SVProgressHUD showWithStatus:#"Deleting" maskType:SVProgressHUDMaskTypeBlack];
loadCount = (int)selectedPhotosURL.count;
NSArray *indexPaths = sortMediaCollection.indexPathsForSelectedItems;
NSMutableArray *pathes = [NSMutableArray arrayWithArray:indexPaths];
NSSortDescriptor *highestToLowest = [NSSortDescriptor sortDescriptorWithKey:#"self" ascending:NO];
[pathes sortUsingDescriptors:[NSArray arrayWithObject:highestToLowest]];
[selecedCellsArray sortUsingComparator:^NSComparisonResult(NSString *str1, NSString *str2) {
return [str2 compare:str1 options:(NSNumericSearch)];
}];
for(NSIndexPath *indexPath in pathes) {
AVMSMCell *cell = (AVMSMCell *)[sortMediaCollection cellForItemAtIndexPath:indexPath];
AVMDataStore *oneItem = [smArray objectAtIndex:indexPath.row];
NSString *contentId = oneItem.fileId;
if (i<selectedPhotosURL.count){
[self deleteUserPhotos:contentId : indexPath.row : cell pathes:pathes]; //pass array with pathes into 'deleteUserPhotos'
i++;
}
}
} else {
[self selectAtLeastOneFirst];
}
}
Main method:
-(void)deleteItemsFromDataSourceAtIndexPaths:(NSArray *)itemPaths {
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
for (NSIndexPath *itemPath in itemPaths) {
[indexSet addIndex:itemPath.row];
}
[smArray removeObjectsAtIndexes:indexSet];
}
-(void)deleteUserPhotos : (NSString *)contentId : (NSInteger )pathRow : (AVMSMCell *) cell pathes:(NSMutableArray*)selectedItemsIndexPaths{
NSNumber *rowNsNum = [NSNumber numberWithUnsignedInt:(unsigned int)pathRow];
if (([selecedCellsArray containsObject:[NSString stringWithFormat:#"%#",rowNsNum]]))
{
cell.selectedBG.backgroundColor = DANGER;
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSString *token = [defaults objectForKey:#"token"];
NSString *header = [NSString stringWithFormat:#"Bearer %#",token];
NSDictionary *params = #{#"lang": #"en",#"content_id":contentId,#"project_id":[defaults objectForKey:#"project_id"]};
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager.requestSerializer setValue:header forHTTPHeaderField:#"Authorization"];
[manager POST:#"http://example.com/api/project/delete-content" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"JSON: %#", responseObject);
if ([[responseObject objectForKey:#"result"] isEqualToString:#"success"]){
#try{
[selecedCellsArray removeObject:[NSString stringWithFormat:#"%ld",(long)pathRow]];
loadCount--;
if (loadCount==0){ //only there remove items from collectionview
// Delete the items from the data source.
[self deleteItemsFromDataSourceAtIndexPaths:selectedItemsIndexPaths];
// Now delete the items from the collection view.
[sortMediaCollection deleteItemsAtIndexPaths:selectedItemsIndexPaths];
[selectedPhotosURL removeAllObjects];
}
} #catch (NSException *e){
NSLog(#"something is bad %#",e);
[SVProgressHUD dismiss];
if (smArray.count<pathRow-1){
[smArray removeObjectAtIndex:(unsigned int)pathRow-1];
}
} #finally {
cell.selectedBG.hidden = YES;
[sortMediaCollection reloadSections:[NSIndexSet indexSetWithIndex:0]];
}
} else {
NSLog(#"can't delete photo!");
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"Error: %#", error);
errorEndSpinner
}];
}
}
Hope this will be helpful for somebody.

I was getting the same error but found that it had to do with a different class having a mirrored copy of the array, and that class accessing a deleted index.
You can add an Exception Breakpoint to see exactly where the exception is coming from. Useful for differentiating errors in your code with errors coming from the iOS SDK: NSRangeException when deleting last UICollectionViewCell

Related

Importing SimpleAuth ForSquareWeb - 9 build time errors

I'm relatively new to objective-c and hardly know much of swift.
I've been trying to make an app which will implement simpleAuth in order to create a link to the ForsquareWeb API.
I'm using cocoapods and have imported the SimpleAuth related files into my product.
Every file seems to be fine except the SimpleAuth target, specifically the SimpleAuthForSquareWebProvider.m file. This is what the file itself looks like;
//
// SimpleAuthFoursquareWebProvider.m
// SimpleAuth
//
// Created by Julien Seren-Rosso on 23/01/2014.
// Copyright (c) 2014 Byliner, Inc. All rights reserved.
//
#import "SimpleAuthFoursquareWebProvider.h"
#import "SimpleAuthFoursquareWebLoginViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
#import "UIViewController+SimpleAuthAdditions.h"
#implementation SimpleAuthFoursquareWebProvider
#pragma mark - SimpleAuthProvider
+ (NSString *)type {
return #"foursquare-web";
}
+ (NSDictionary *)defaultOptions {
// Default present block
SimpleAuthInterfaceHandler presentBlock = ^(UIViewController *controller) {
UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:controller];
navigation.modalPresentationStyle = UIModalPresentationFormSheet;
UIViewController *presented = [UIViewController SimpleAuth_presentedViewController];
[presented presentViewController:navigation animated:YES completion:nil];
};
// Default dismiss block
SimpleAuthInterfaceHandler dismissBlock = ^(id controller) {
[controller dismissViewControllerAnimated:YES completion:nil];
};
NSMutableDictionary *options = [NSMutableDictionary dictionaryWithDictionary:[super defaultOptions]];
options[SimpleAuthPresentInterfaceBlockKey] = presentBlock;
options[SimpleAuthDismissInterfaceBlockKey] = dismissBlock;
return options;
}
- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion {
[[[self accessToken]
flattenMap:^RACStream *(NSString *response) {
NSArray *signals = #[
[self accountWithAccessToken:response],
[RACSignal return:response]
];
return [self rac_liftSelector:#selector(dictionaryWithAccount:accessToken:) withSignalsFromArray:signals];
}]
subscribeNext:^(NSDictionary *response) {
completion(response, nil);
}
error:^(NSError *error) {
completion(nil, error);
}];
}
#pragma mark - Private
- (RACSignal *)accessToken {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
dispatch_async(dispatch_get_main_queue(), ^{
SimpleAuthFoursquareWebLoginViewController *login = [[SimpleAuthFoursquareWebLoginViewController alloc] initWithOptions:self.options];
login.completion = ^(UIViewController *login, NSURL *URL, NSError *error) {
SimpleAuthInterfaceHandler dismissBlock = self.options[SimpleAuthDismissInterfaceBlockKey];
dismissBlock(login);
// Parse URL
NSString *fragment = [URL fragment];
NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:fragment];
NSString *token = dictionary[#"access_token"];
// Check for error
if (![token length]) {
[subscriber sendError:error];
return;
}
// Send completion
[subscriber sendNext:token];
[subscriber sendCompleted];
};
SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey];
block(login);
});
return nil;
}];
}
- (RACSignal *)accountWithAccessToken:(NSString *)accessToken {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSDictionary *parameters = #{ #"oauth_token" : accessToken };
NSString *query = [CMDQueryStringSerialization queryStringWithDictionary:parameters];
NSString *URLString = [NSString stringWithFormat:#"https://api.foursquare.com/v2/users/self?v=20140210&%#", query];
NSURL *URL = [NSURL URLWithString:URLString];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
[NSURLConnection sendAsynchronousRequest:request queue:self.operationQueue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 99)];
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if ([indexSet containsIndex:statusCode] && data) {
NSError *parseError = nil;
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&parseError];
if (dictionary) {
[subscriber sendNext:dictionary];
[subscriber sendCompleted];
}
else {
[subscriber sendError:parseError];
}
}
else {
[subscriber sendError:connectionError];
}
}];
return nil;
}];
}
- (NSDictionary *)dictionaryWithAccount:(NSDictionary *)account accessToken:(NSString *)accessToken {
NSMutableDictionary *dictionary = [NSMutableDictionary new];
NSDictionary *userData = account[#"response"][#"user"];
// Provider
dictionary[#"provider"] = [[self class] type];
// Credentials
dictionary[#"credentials"] = #{
#"token" : accessToken
};
// User ID
dictionary[#"uid"] = userData[#"id"];
// Raw response
dictionary[#"extra"] = #{
#"raw_info" : userData
};
// User info
NSMutableDictionary *user = [NSMutableDictionary new];
if (userData[#"contact"][#"email"]) {
user[#"email"] = userData[#"contact"][#"email"];
}
if (userData[#"firstName"]) {
user[#"first_name"] = userData[#"firstName"];
}
if (userData[#"lastName"]) {
user[#"last_name"] = userData[#"lastName"];
}
user[#"name"] = [NSString stringWithFormat:#"%# %#", user[#"first_name"], user[#"last_name"]];
user[#"gender"] = userData[#"gender"];
if ([userData[#"photo"] isKindOfClass:NSDictionary.class]) {
user[#"image"] = [NSString stringWithFormat:#"%#500x500%#", userData[#"photo"][#"prefix"], userData[#"photo"][#"suffix"]];
} else if ([userData[#"photo"] isKindOfClass:NSString.class]) {
user[#"image"] = userData[#"photo"];
}
if (userData[#"photo"]) {
user[#"photo"] = userData[#"photo"];
}
if (userData[#"homeCity"]) {
NSString *homecity = [[userData[#"homeCity"] componentsSeparatedByString:#","] firstObject];
user[#"location"] = homecity;
}
user[#"urls"] = #{
#"Foursquare" : [NSString stringWithFormat:#"https://foursquare.com/user/%#", userData[#"id"]],
};
dictionary[#"info"] = user;
return dictionary;
}
#end
I think it would be easier to show you just a screen shot of the errors and where they're arising in the code itself;
I would really appreciate some insight into where the problem lies. I'm not sure why many of the errors say use of undeclared identifiers, are the imported files not correct?
After trying to re-install the pod file as it was suggested a class hadn't been installed I still have the same problem. Here are screen shots of my podfile and the terminals output when installing the pods;
I just used the Cocoapods application rather than terminal. I got additional information when clicking install.
"[!] The dPicDid [Debug] target overrides the ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES build setting defined in `Pods/Target Support Files/Pods-dPicDid/Pods-dPicDid.debug.xcconfig'. This can lead to problems with the CocoaPods installation
[!] The dPicDid [Release] target overrides the ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES build setting defined in Pods/Target Support Files/Pods-dPicDid/Pods-dPicDid.release.xcconfig'. This can lead to problems with the CocoaPods installation
- Use the$(inherited)flag, or
- Remove the build settings from the target.
- Use the$(inherited)` flag, or
- Remove the build settings from the target.

NSSearch Field Predicate Filter

-(void) searchFieldChanged{
MPVTModelList *list = [[MPVTModelList alloc] initWithClass:[MassPOAssignmentModel class]];
[intersectionTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
// [searchIntersectionField setStringValue:[[[searchIntersectionField stringValue] stringByReplacingOccurrencesOfString:#"\\" withString:kMPVTBlankString] stringByReplacingOccurrencesOfString:#"\'" withString:kMPVTBlankString]];
[searchIntersectionField setStringValue:[searchIntersectionField stringValue]];
NSArray *array=[[NSArray alloc]init];
if([[[searchIntersectionField cell]placeholderString] isEqualToString:#"Pricing Org"]){
NSArray *tempArray=[[[searchIntersectionField stringValue] uppercaseString] componentsSeparatedByString:#","];
NSLog(#"tempArray %#",tempArray);
NSString * str=[[searchIntersectionField stringValue] uppercaseString];
NSLog(#"str is %#",str);
for(id item in tempArray ){
[intersectionTableView reloadData];
array=[[[self intersectionList]entities]filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"mpoPricingOrg.stringValue contains[cd] %#",item]];
NSLog(#" item is %#",item);
NSLog(#"insie if arr %#",array);
[list appendEntities:array];
NSLog(#"hello %#",[[searchIntersectionField cell]placeholderString]);
}
}
else{
NSLog(#"inside else");
array = [[self searchFieldController] updatePredicateWithFilterText:[searchIntersectionField stringValue] searchArray:[[self intersectionList] entities] searchTableView:intersectionTableView];
NSLog(#"in side else array %#",array);
[list appendEntities:array];
}
[self setIntersectionList:list];
[list release];
[intersectionTableView reloadData];
[intersectionTableView deselectAll:nil];
[super updatePlacard:intersectionTableView];
}
I have called this method in -(void)controltextDidEditing. But when I enter "China" the filter predicate works fine. But when I enter "China,Brazil" it only shows the record for China and not for Brazil. Please suggest a better way of doing it.

CoreData and UITableView: display values in cells

I'm working with Core Data and web service, I want to add my data to my table,
but I don't know how should I call them, would you please help me, since when I used this way it's not working.
Here is my method for update database in my HTTP class
- (void)updateLocalCardsDataBase:(NSArray*) cardsArray
{
//check if current user has cards in local database
NSManagedObjectContext* managedObjectContext = [(AppDelegate*) [[UIApplication sharedApplication] delegate] managedObjectContext];
for(NSDictionary *cardDic in cardsArray)
{
Card *card = [NSEntityDescription insertNewObjectForEntityForName:#"Card" inManagedObjectContext:managedObjectContext];
card.remote_id = [NSNumber numberWithInt:[[cardDic objectForKey:#"id"] intValue]];
card.stampNumber = [NSNumber numberWithInt:[[cardDic objectForKey:#"stampNumber"] intValue]];
card.createdAt = [NSDate dateWithTimeIntervalSince1970:[[cardDic objectForKey:#"createdAt"] intValue]];
[managedObjectContext lock];
NSError *error;
if (![managedObjectContext save:&error])
{
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
NSLog(#"Failed to save to data store: %#", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0) {
for(NSError* detailedError in detailedErrors) {
NSLog(#" DetailedError: %#", [detailedError userInfo]);
}
}
else {
NSLog(#" %#", [error userInfo]);
}
}
[managedObjectContext unlock];
}
Here is my table:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
// NSManagedObjectContext* managedObjectContext = [(AppDelegate*) [[UIApplication sharedApplication] delegate] managedObjectContext];
static NSString *CellIdentifier = #"CardsCell";
CardCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil){
NSArray *objects = [[NSBundle mainBundle] loadNibNamed:#"CardCell" owner:nil options:nil];
for (id currentObject in objects)
{
if([currentObject isKindOfClass:[UITableViewCell class]])
{
cell = (CardCell *) currentObject;
break;
}
}
NSDictionary *f = [_cards objectAtIndex:indexPath.row];
cell.stampId.text = [f objectForKey:#"stampNumber"];
NSLog(#"%#fdssfdfddavds",[f objectForKey:#"stampNumber"]);
cell.createdAt.text = [f objectForKey:#"createdAt"];
cell.CardId.text = [f objectForKey:#"id"];
return cell;
}
Edit:
My problem is how I can show data in a UITableView
Before call [tableView reloadData], you need to get a data source first. You will get back an array of your data models, not an NSDictionary. You can place the my example method (or a variation that suits you best) where ever best suits your needs, but this one will not filter or sort the models, it will only get all of them. Also, I will place the method in your view controller that stores the table view:
-(NSArray*)getMycards {
NSManagedObjectContext *context = [(AppDelegate*) [[UIApplication sharedApplication] delegate] managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Card" inManagedObjectContext:context];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
NSError *error;
[request setEntity:entityDescription];
NSArray *cards = [context executeFetchRequest:request error:&error];
// now check if there is an error and handle it appropriatelty
// I usually return 'nil' but you don't have if you don't want
if ( error != nil ) {
// investigate error
}
return cards;
}
I recommend creating a property #property NSArray *cards in the view controller where you place your table, it will be easier to manage. One assumption I have made (since I have no other information about your view controller, a property named 'tableView' is declared in your view controller's header file (#property UITableView *tableView;), adjust the naming as needed.
With the above method, when you want to populate your array before loading the table's data:
// you put this block of code anywhere in the view controller that also has your table view
// likely in 'viewDidLoad' or 'viewDidAppear'
// and/or anywhere else where it makes sense to reload the table
self.cards = [self getMyCards];
if ( self.cards.count > 0 )
[self.tableview reloadData];
else {
// maybe display an error
}
Now, your cellForRowAtIndexPath should look like
-(UITableViewCell*tableView:tableView cellForRowAtIndexPath {
UITbaleViewCell *cell = ...;
// creating the type of cell seems fine to me
.
.
.
// keep in mind I don't know the exact make up of your card model
// I don't know what the data types are, so you will have to adjust as necessary
Card *card = self.cards[indexPath.row];
cell.stampId.text = [[NSString alloc] initWithFormat:#"%#",card.stamp];
cell.createdAt.text = [[NSString alloc] initWithFormat:#"%#",card.createdAt];
// you might want format the date property better, this might end being a lot more than what you want
cell.CardId.text = [[NSString alloc] initWithFormat:#"%#",card.id];
return cell;
}
Core Data is extremely powerful, I highly recommend the Core Data overview, followed by the Core Data Programming Guide.

NRGridView won't show data from my core data database

I am building a app for a local football club. I want to show all players names and pictures in a grid. Therefore I am using the NRGridview. But it won't load up with my data. I have an NSArray with all players information. Here you see the method which generates this array.
- (NSArray *)getTeam
{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Team"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"sortOrder" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
NSError *error = nil;
NSArray *mutableFetchResults = [self.genkDatabase.managedObjectContext executeFetchRequest:request error:&error];
NSLog(#"first error log %#", [error localizedDescription]);
if (mutableFetchResults == nil) {
NSLog(#"second error log %#", [error localizedDescription]);
}else if ([mutableFetchResults count] == 0){
NSLog(#"geen resultaten voor team");
}else{
NSLog(#"team names: %#",[mutableFetchResults valueForKey:#"name"]);
return mutableFetchResults;
}
return mutableFetchResults;
}
And this is what I do in the tableview.
- (NRGridViewCell*)gridView:(NRGridView *)gridView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyCellIdentifier = #"MyCellIdentifier";
NRGridViewCell* cell = [gridView dequeueReusableCellWithIdentifier:MyCellIdentifier];
if(cell == nil){
cell = [[NRGridViewCell alloc] initWithReuseIdentifier:MyCellIdentifier];
[[cell textLabel] setFont:[UIFont boldSystemFontOfSize:11.]];
[[cell detailedTextLabel] setFont:[UIFont systemFontOfSize:11.]];
}
NSLog(#"players array %#",players);
for (int i = 0; i <= [players count]; i++) {
// NSData *imgData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[[players objectAtIndex:i]valueForKey:#"image"]]];
// UIImage *image = [[UIImage alloc]initWithData:imgData];
//cell.imageView.image = image;
cell.textLabel.text = [[players objectAtIndex:i]valueForKey:#"name"];
cell.detailedTextLabel.text = [[players objectAtIndex:i]valueForKey:#"position"];
return cell;
}
return cell;
}
The NSLog gives always (null). My question is now, where should I put the code "NSArray *players = [self getTeam] . so that my tableview will fill up with data?
EDIT
It did give me back the right amount of sections, and numberOfRowsInsection. For numbersOfRowsIn section I created 4 methods. 1 method whichs gets all off the goalkeepers, 1 for the defenders, 1 for the wingers, and 1 for the attackers. Then In my tableview method I did the following.
- (NSInteger)gridView:(NRGridView *)gridView numberOfItemsInSection:(NSInteger)section
{
if(section == 0){
return [[self getDoelmannen]count];
}else if (section == 1){
return [[self getVerdedigers]count];
}else if (section == 2){
return [[self getMiddenvelders]count];
}else{
return [[self getAanvallers]count];
}
return [[self getAanvallers]count];
}
This works. But still have the problem for my cell self.
EDIT2
Okay I think my problem is with filling my players Array up. I do the following in my viewDidLoad
-(void)viewDidLoad{
_players = [self getTeam];
NSLog(#"players array: %#",_players);
}
Which gives the following log.
2012-10-17 12:11:22.099 RacingGenk[63122:c07] nil
2012-10-17 12:11:22.099 RacingGenk[63122:c07] players array: (null)
Here is my code for getTeam
- (NSArray *)getTeam
{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Team"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"sortOrder" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
NSError *error = nil;
NSArray *mutableFetchResults = [self.genkDatabase.managedObjectContext executeFetchRequest:request error:&error];
if (mutableFetchResults == nil) {
NSLog(#"nil");
}else if ([mutableFetchResults count] == 0){
NSLog(#"geen resultaten voor team");
}else{
NSLog(#"team names: %#",[mutableFetchResults valueForKey:#"name"]);
return mutableFetchResults;
}
return mutableFetchResults;
}
It looks like players isn't getting initialized. You can put your [self getTeam] call in the viewDidLoad method and make players a property.
If NRGridView is anything like UITableView, there are probably other methods that you need to overload.
For example, UITableView has tableView:numberOrRowsInSection:. Failure to return > 0 value from this method results in nothing being shown. Or numberOfSectionsInTableView:, which returns the number of sections and so on.
Check the documentation for the control you're using.
Update:
Since your executeFetchRequest:error: is failing, you should check if there's an error message instead of just printing out (nil):
NSLog(#"%#", [error localizedDescription]);

assign value from NSDictionary to NSManagedObject

My app requires to get data from a .Net WCF service when the device is connected to WiFi.If there's a new row added on the server,it should add it to its CoreData database. I am using a NSDictionary for comparing the local objects with the remote objects. The code is:
-(void)handleGetAllCategories:(id)value
{
if([value isKindOfClass:[NSError class]])
{
NSLog(#"This is an error %#",value);
return;
}
if([value isKindOfClass:[SoapFault class]])
{
NSLog(#"this is a soap fault %#",value);
return;
}
NSMutableArray *result = (NSMutableArray*)value;
NSMutableArray *remoteObj = [[NSMutableArray alloc]init];
for (int i = 0; i < [result count]; i++)
{
EDVCategory *catObj = [[EDVCategory alloc]init];
catObj = [result objectAtIndex:i];
[remoteObj addObject:catObj];
}
NSArray *remoteIDs = [remoteObj valueForKey:#"categoryId"];
NSFetchRequest *request = [[[NSFetchRequest alloc] init]autorelease];
request.predicate = [NSPredicate predicateWithFormat:#"categoryId IN %#", remoteIDs];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Categories" inManagedObjectContext:__managedObjectContext];
[request setEntity:entity];
NSMutableArray *results = [[NSMutableArray alloc]initWithArray:[__managedObjectContext executeFetchRequest:request error:nil]];
NSArray *existingIDs = [results valueForKey:#"categoryId"];
NSDictionary *existingObjects = [NSDictionary dictionaryWithObjects:results forKeys:existingIDs];
for (NSDictionary *remoteObjectDic in remoteObj)
{
Categories *existingObject = [existingObjects objectForKey:[remoteObjectDic valueForKey:#"categoryId"]];
if (existingObject)
{
NSLog(#"object exists");
}
else
{
NSLog(#"create new local object");
// Categories *newCategory;
// newCategory = [NSEntityDescription insertNewObjectForEntityForName:#"Categories" inManagedObjectContext:__managedObjectContext];
// [newCategory setCategoryId:[NSNumber numberWithInt:[[remoteObjectDic objectForKey:#"categoryId"]intValue]]];
// [newCategory setCategoryName:[remoteObjectDic objectForKey:#"categoryName"]];
// [newCategory setDocCount:[NSNumber numberWithInt:[[remoteObjectDic objectForKey:#"docCount"]intValue]]];
// [newCategory setCategoryType:[NSNumber numberWithInt:[[remoteObjectDic objectForKey:#"categoryType"]intValue]]];
// [newCategory setSubCategoryId:[NSNumber numberWithInt:[[remoteObjectDic objectForKey:#"subCategoryId"]intValue]]];
// [__managedObjectContext insertObject:newCategory];
}
}
[my_table reloadData];
}
The problem is,I am not able to extract values from the remote object and assign it to the NSManagedObject.I have commented the code which (according to me) should save the values in new object to the managed object. Can someone please help me achieve this?
Thanks
Here is an example of a save I did in a recent project. I have somethings in wrappers so fetching a managed object and saving look a little weird on my end. Really the only major difference I see is the act of saving. Are you saving the new NSManagedObject elsewhere in the code?
dict = (NSDictionary*)data;
#try {
if (dict) {
CaretakerInfo* info = [GenericDataService makeObjectWithEntityName:NSStringFromClass([CaretakerInfo class])];
[info setName:[dict valueForKey:#"name"]];
[info setImageURL:[dict valueForKey:#"photo"]];
[info setCaretakerID:[dict valueForKey:#"id"]];
[GenericDataService save];
}
else {
theError = [Error createErrorMessage:#"No Data" Code:-42];
}
}
#catch (NSException *exception) {
//return an error if an exception
theError = [Error createErrorMessage:#"Exception Thrown While Parsing" Code:-42];
}
If not it should looks something like this...
NSError *error = nil;
[context save:&error];
If you have anymore information about what's happening when you extract or assigning data that would be helpful (error/warning/log messages).