when I fetch the record from core data it returns null value...i don't know what is the problem...
When I check in NSLog it shows like this:
"<Ad: 0x979fb30> (entity: Ad; id: 0x9799470 <x-coredata://B3AA111F-8307-4A16-B898-
403A804DFDFB/Ad/p22> ; data: <fault>)",
"<Ad: 0x979fd70> (entity: Ad; id: 0x9799480 <x-coredata://B3AA111F-8307-4A16-B898-
403A804DFDFB/Ad/p23> ; data: <fault>)
Here is my code.
I returned all the core data functions in separate class called dbmanager.
- (void)viewDidLoad
{
DBManager *manager=[[DBManager alloc]init];
self.fetchedRecordsArray = [manager fetchAllAds];
[self.shoppingtbl reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.fetchedRecordsArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
{
static NSString *CellIdentifier = #"ShoppingCart";
ShoppingCart *cell = (ShoppingCart*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
cell.backgroundColor=[UIColor clearColor];
ad=[self.fetchedRecordsArray objectAtIndex:indexPath.row]
cell.addesc.text = ad.data;
cell.adId.text=[NSString stringWithFormat:#"%lu", (long)[ad.adId integerValue]];
cell.adstatus.text=[NSString stringWithFormat:#"%#",ad.state];
return cell;
}
The entity name called Ad. It contains Adid,state,data.
In table view it shows null value for strings and 0 for numbers..
I recommend you abandon your fetchedRecordsArray and embrace the NSFetchedResultsController. It is specifically designed to work with core data and table views.
This will almost certainly eliminate the problem you have and result in much more robust and scalable code. You could be displaying 100.000s ads this way without any problem.
One more hint, i.e. something you might want to check beforehand: quite possibly you did not save the data correctly. It looks like you saved each record with [managedObjectContext save:&error] after it was created, but perhaps you did not do this correctly after populating it with state, data. The way to check this is to enumerate your array elements and NSLog those bits of information to check if they are there.
Related
my question is, if it is possible to display a cell only if there is data present for a specific post. I'm thinking something along the line of this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
PFQuery *query = [PFQuery queryWithClassName:#"Post"];
if(![query includeKey:#"Photo"]) {
UITableViewCell *cell = [self tableView:tableView cellForNextPageAtIndexPath:indexPath];
return cell;
}
static NSString *CellIdentifier = #"PhotoCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
PFImageView *photo = (PFImageView *)[cell viewWithTag:1];
photo.file = object[#"image"];
[photo loadInBackground];
return cell;
}
I've tried this but i can not get it to work every which way try, any help will be apreciated, thank you in advanced.
Tables need a model, and that model is almost always an array. The datasource protocol's job is to ask about that array.
So what's in your array? Sometimes nothing, because you haven't fetched the data for it yet, or because the user has no data that belongs there. From your question, it sounds like sometimes your array has 1 element -- something representing a post or an image -- and sometimes your array has 2 elements -- something representing a post and an image.
Thinking this way lets you divide your work into two parts: (1) do a fetch and create an array that represents the current state, (2) implement a table that presents the state of that array to the user.
Lets start with the array (note this is pseudo-code, meant to illustrate the idea):
// in interface
#property(strong,nonatomic) NSMutableArray *model;
// in init
_model = [NSMutableArray array];
// sometime at or after viewDidAppear, update your model by querying parse
// I don't understand your parse data model, but you want some query
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// based on the parse objects returned, initialize model
[self.model addObject: ...];
// tell your table that the model has changed
[self.tableView reloadData];
}
}];
With your array handled elsewhere, the datasource job is simpler:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.model.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// dequeue a cell, configure its subviews based on self.model[indexPath.row]
// no parse code here. aim to configure the cell strictly based on the model
return cell;
}
Notice how the table view is ignorant of parse.com and the parse code is largely ignorant of the table view.
I have 2 UITableViewControllers in my project.
The problem I am having is that I am getting blank cell entries in the tableView opposite to the tableView where the data is entered.
I can't seem to figure out why this is the case.
It's creating blank rows in this tableView even though the information is from the other UITableViewController.
Here's the main tableView part from the one of the 2 UITableViewControllers:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSLog(#"number of addedSpaceObjects %lu",(unsigned long)[self.diaryoptions count]);
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"number of sections %ld",(long)section);
// Return the number of rows in the section.
return [self.diaryoptions count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentification = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentification
forIndexPath:indexPath];
Data2 *diary = [self.diaryoptions objectAtIndex:indexPath.row];
cell.textLabel.text = diary.diaryname;
cell.detailTextLabel.text = diary.diaryWeight;
return cell;
}
And from other UITableViewController:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSLog(#"number of addedSpaceObjects %lu",(unsigned long)[self.addedSpaceObjects count]);
// Return the number of sections.
if ([self.addedSpaceObjects count]) {
return 2;
}
else {
return 1;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"number of sections %ld",(long)section);
// Return the number of rows in the section.
if (section == 1) {
return [self.addedSpaceObjects count];
}
else {
return [self.recipes count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentification = #"Josh";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentification
forIndexPath:indexPath];
if (indexPath.section == 1) {
Data *recipe = [self.addedSpaceObjects objectAtIndex:indexPath.row];
cell.textLabel.text = recipe.name;
}
else {
// Configure the cell...
Data *recipe = [self.recipes objectAtIndex:indexPath.row];
cell.textLabel.text = recipe.name;
}
return cell;
}
Here is the full project on GitHub. https://github.com/josher32/Plant-Diet
Appreciate any help anyone can offer!
Ok, so I checked out the app and I'll try my best to explain the problem as precisely as I can to cover it adequately.
Firstly, the classes in question are:
RecipesTableTableViewController
AddRecipeViewController
Data
DiaryTableViewController
AddDiaryViewController
Data2
Secondly, we'll need to look into your
#define ADDED_SPACE_OBJECTS2 #"Added Space Objects Array"
AddRecipeViewController
So... AddRecipeViewController basically creates a Data object that is kept in an array and eventually stored in NSUserDefaults under the key name Added Space Objects Array.
Great!! So you now have got recipe related stuff in some Data object.
AddDiaryViewController
Same thing here.
AddDiaryViewController creates a Data2 object that is eventually stored in NSUserDefaults under the same key name Added Space Objects Array.
But before storing this, you're taking the old value of the key Added Space Objects Array, which is an array, and adding a new object to it before placing it back into NSUserDefaults.
But now... this array will now have a combination of Data as well as Data2 objects!
RecipesTableTableViewController
When we come here, things get real.
- (void)viewDidLoad
{
//...
NSArray *myRecipeAsPropertyLists = [[NSUserDefaults standardUserDefaults] arrayForKey:ADDED_SPACE_OBJECTS_KEY];
for (NSDictionary *dictionary in myRecipeAsPropertyLists) {
Data *spaceObject = [self spaceObjectForDictionary:dictionary];
[self.addedSpaceObjects addObject:spaceObject];
}
}
Since we already realized that self.addedSpaceObjects can contain Data as well as Data2 objects, in the case whendictionary is containing stuff specific to type Data2, spaceObjectForDictionary will not be able to translate it properly to the required Data object.
We're expecting name, title, ingredients, directions but we're getting diaryentry, diaryname,diaryWeight.
So (in this scenario):
The values of name, title, ingredients, directions will be nil
The section-row count will be incorrect because it will give count of both Data as well as Data2 objects (and we don't care about Data2 objects in the RecipesTableTableViewController class... right?... well anyways, I assumed)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//...
if (indexPath.section == 1) {
Data *recipe = [self.addedSpaceObjects objectAtIndex:indexPath.row];
cell.textLabel.text = recipe.name;
}
//...
}
We see recipe.name is nil, for some indexPaths, ergo blank rows and vice versa in DiaryTableViewController.
Solution:
Firstly, I wouldn't recommend NSUserDefaults for your purposes but anyways...
Basically, don't use a single #"Added Space Objects Array" key for your NSUserDefaults stuff.
I'd suggest you use 2 separate keys.
//replace
//#define ADDED_SPACE_OBJECTS2 #"Added Space Objects Array"
//with
#define ADDED_SPACE_OBJECTS2 #"RecipeEntries" //in RecipesTableTableViewController
//and
#define ADDED_SPACE_OBJECTS2 #"DiaryEntries" //in DiaryTableViewController
Basically, segregate the entries instead of mixing them up under a single key name.
This seems like the quickest way to solve your problem without changing your logic.
I am have an NSDictionary which multiple dictionaries like this:
{
complete = 0;
description = Description;
"due_date" = "2014-02-28 16:30:03";
name = Task;
priority = 2;
"task_id" = 1;
"user_id" = 1;
},
{
complete = 0;
description = "";
"due_date" = "0000-00-00 00:00:00";
name = "";
priority = 0;
"task_id" = 2;
"user_id" = 1;
}
I would like to display each instance of "name" in my UITableView
I have tried this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
for (task in tasks) {
cell.textLabel.text = [[task objectAtIndex:indexPath.row] valueForKey:#"name"];
}
return cell;
}
But the app crashes each time I attempt to do run it.
What am I doing wrong?
Here is the error I get:
Assertion failure in -[UITableView _configureCellForDisplay:forIndexPath:]
Change your code to look like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
cell.textLabel.text = [[tasks objectAtIndex:indexPath.row] valueForKey:#"name"];
return cell;
}
The problem was that task was a dictionary, so it didn't respond to objectAtIndex:.
BTW, you need to create or dequeue a UITableViewCell instance as well, but I simply corrected your crashing issue for you.
The reason you are getting a crash is because you are returning nil from tableView:cellForRowAtIndexPath:.
I think you are also misunderstanding how this table view data source method works. It gets called once per table cell in your table (hence why you return a UITableViewCell from it...). You don't need to be looping over your data collection inside it - you should be getting the correct data object from your collection based on the indexPath.
On top of that, as others have said, if tasks is in fact an NSDictionary, then it won't respond to objectAtIndex. In all likelihood, you probably want your data collection to be an NSArray, if it isn't already.
Edit:
Judging by the error you are getting, tasks is in fact an NSArray (as the error is caused by returning nil from tableView:cellForRowAtIndexPath:). Try the following:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCellIdentifier" forIndexPath:indexPath];
NSDictionary *task = [tasks objectAtIndex:indexPath.row];
cell.textLabel.text = [task objectForKey:#"name"];
return cell;
}
Edit 2:
Also, you should be using objectForKey: instead of valueForKey:.
Dictionaries don't have indices.
You can't call a objectAtIndex: method on a dictionary, that's why your app is crashing. Instead, you need to use objectForKey: with the appropriate key to get the value you want.
Try storing those NSDictionary's in an NSArray. An NSArray will allow you to hold them, along with accessing objects with "objectAtIndex".
If you need to add NSDictionary's at run-time, try using an NSMutableArray, which allows you to add and remove array objects when needed.
I'm using this to count all the uncompleted reminders in the defult list and put it in the detail of the table view cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
NSPredicate *predicate2 = [self.reminderStore predicateForIncompleteRemindersWithDueDateStarting:nil ending:nil calendars:#[[self.reminderStore defaultCalendarForNewReminders]]];
[self.reminderStore fetchRemindersMatchingPredicate:predicate2 completion:^(NSArray *reminders)
{
cell.detailTextLabel.text = [NSString stringWithFormat:#"%d", [reminders count]];
NSLog(#"count: %d", [reminders count]);
}];
...
return cell;
}
The problem is that because it's on another thread, it's not updating the table cell until it needs to reload it. (it does prints in the log). What's the best way of fixing that, so it would load automatically and won't need to load again every time? Also, is there another way to faster count reminders?
I´m quite new to iOS development and I´m having a terrible time by trying something that should be easy; to add an extra row in a TableView everytime the user clicks on one of the existing rows. There is no real purpose on that action, I´m just wanting to understand the behaviour of TableView.
So I did the following:
I used a Split View-based template and changed the number of rows to 30 in the RootViewController.
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return 30;
}
The method tableView:didSelectRowAtIndexPath looks in the following manner:
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
/*
When a row is selected, set the detail view controller's detail item to the item associated with the selected row.
*/
NSMutableArray* paths = [[NSMutableArray alloc] init];
NSIndexPath *indice = [NSIndexPath indexPathForRow:30 inSection:0];
[paths addObject:indice];
detailViewController.detailItem = [NSString stringWithFormat:#"Second Story Element %d with all its information and bla bla bla", indexPath.row];
[[self tableView] beginUpdates];
[self.tableView insertRowsAtIndexPaths:(NSArray *) paths withRowAnimation:UITableViewRowAnimationNone];
[[self tableView] endUpdates];
}
When I execute the program and click on one of the elements, I receive the following error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (30) must be equal to the number of rows contained in that section before the update (30), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted).'
I did not change any other part of the code that the template provides.
I read quite extensively the documentation from Apple and the responses to the following questions:
Add a row dynamically in TableView of iphone
and
how to properly use insertRowsAtIndexPaths?
The second question seems to address the same problem, but I´m not capable to understand what is happening. What do they mean with dataSource? The response that I understand better says the following:
It's a two step process:
First update your data source so numberOfRowsInSection and cellForRowAtIndexPath will return the correct values for your post-insert data. You must do this before you insert or delete rows or you will see the "invalid number of rows" error that you're getting.
What does this update of the data source implies?
Sample code would be HIGHLY appreciated, because I´m totally frustrated.
By the way, all that I´m trying has nothing to do with entering the editing mode, has it?
You need to keep the count returned by tableView:numberOfRowsInSection: in sync!
So when you have 30 rows and then tell the tableview to insert a new row you need to make sure tableView:numberOfRowsInSection: will now return 31.
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section
{
return self.rowCount;
}
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.rowCount++;
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:(NSArray *) paths withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
}
In practice you would probably use an array to track your rows return [self.rows count]; etc
The answer is quite simple. When you want to modify a table view you need to perform two simple steps:
Deal with the model
Deal with table animation
You already perform the second step. But you have missed the first one. Usually when you deal with a table you pass it a data source. In other words some data to display within it.
A simple example is using a NSMutableArray (it's dynamic as the name suggests) that contains dummy data.
For example, create a property like the following in .h
#property (nonatomic, strong) NSMutableArray* myDataSource;
and in .m synthesize it as:
#synthesize myDataSource;
Now, you can alloc-init that array and populate it as the following (for example in viewDidLoad method of your controller).
self.myDataSource = [[NSMutableArray alloc] init];
[self.myDataSource addObject:#"First"];
[self.myDataSource addObject:#"Second"];
Then, instead of hardcoding the number of rows you will display (30 in your case), you can do the following:
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
return [self.myDataSource count];
}
Now, in you didSelectRowAtIndexPath delegate you can add a third element.
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.myDataSource addObject:#"Third"];
[[self tableView] beginUpdates];
[self.tableView insertRowsAtIndexPaths:(NSArray *) paths withRowAnimation:UITableViewRowAnimationNone];
[[self tableView] endUpdates];
}
It looks like one big problem is with tableView:numberOfRowsInSection:. You need to return the correct number of rows in that method.
To do that, it's usually best to maintain an NSArray or NSMutableArray of items for the table view so in that function, you can say: return [arrayOfValues count];. Keep the array as a property of your view controller class so that it's readily accessible in all methods.
The array can also be used in cellForRowAtIndexPath:. If you have an array of NSString, you can say cell.text = [arrayOfValues objectAtRow:indexPath.row];.
Then, when you want to add an item to the table view, you can just add it to the array and reload the table, e.g. [tableView reloadData];.
Try implementing this concept and let me know how it goes.
You can Also do that for dayanamic table cell
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [arrayStationStore count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIndentyfire;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIndentyfire];
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIndentyfire];
}
cell.textLabel.text = [arrayStationStore objectAtIndex:indexPath.row];
return cell;
}
-(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Check if current row is selected
BOOL isSelected = NO;
if([tblStationName cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryCheckmark)
{
isSelected = YES;
}
if(isSelected)
{
[tblStationName cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
[arrayReplace removeObject:indexPath];
NSLog(#"array replace remove is %# ",arrayReplace);
}
else
{
[tblStationName cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
[arrayReplace addObject:indexPath];
NSLog(#"array replace add is %# ",arrayReplace);
}
return indexPath;
}