Dynamic sections with dynamic cells with Core Data? - xcode

I am really close to the solution, but i cannot figure out the rest, so i am asking for help now...
I use core data, so I'd like to show, whats inside of it.
Here is my code so far:
at .m
#property NSMutableArray *users, *sharedWishes;
- (void)viewDidLoad
{
[super viewDidLoad];
AppDelegate *delegate=[UIApplication sharedApplication].delegate;
self.context=delegate.managedObjectContext;
self.users=delegate.collectUserNames; //collect every users from database
self.sharedWishes=[delegate collectSharedWishes]; //collect every wish from DB - each user has different number of records
[self.tableView reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// works great so far
return self.users.count;
}
-(NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
User *user=[self.users objectAtIndex:section]; //shows the username for each section
if(self.users.count<1)
return #"no friends";
else
return user.userName; //this is just fine, too
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
SharedWishes *wish=[self.sharedWishes objectAtIndex:indexPath.row]; //this is where the problem is...the tableview shows the records until the other user records starts
static NSString *identifier=#"Cell";
Cell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
...
}
So, any suggestion for the cellForRowAtIndexPath:, what should I add?
Every section should have a title (which has) for the current user name, and every section should contain that particular person's records (which fails). Instead, when new section begins (with new user) the existing records starting to repeat. How should I avoid it?
Thanks in advance!
EDIT: added this few line to cellForRowAtIndexPath:
User *user=[self.users objectAtIndex:indexPath.section];
AppDelegate *delegate=[UIApplication sharedApplication].delegate;
self.currentUserWishes=[delegate collectCurrentUserSharedWishes:user];
Now it works!

Related

xcode Converting UITableView to UICollectionView (no valid cell)

EDIT: I should specify that this only happens when I attempt to use the UICollectionViewFlowLayout, not when I try to use a custom view. But either way nothing ever shows up on the CollectionView though it was working just fine before I converted from a TableView.)
So I've been trying to convert a UITableView that I had into a UICollectionView. So far so good. But when I try to run the app it gives me the error:
'the collection view's data source did not return a valid cell from -collectionView:cellForItemAtIndexPath: for index path {length = 2, path = 0 - 0}'
I checked all the similar questions and answers here... so in my viewDidLoad I have (tableView is actually a UICollectionView):
UINib * placeCell = [UINib nibWithNibName:#"Shops" bundle:nil];
[self.tableView registerNib:placeCell
forCellWithReuseIdentifier:CellIdentifier];
#pragma mark - UICollectionViewDataSource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UICollectionView *)tableView numberOfItemsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [_entries count];
//return 5;
}
- (void)tableView:(UICollectionView *)tableView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.item == [_entries count]-1 && page > 1) {
NSLog(#"load more");
//add footer view loading
if (c_page == page) {
// _tableView.tableFooterView = nil;
}
else
{
c_page++;
[self loadPlace:c_page];
}
}
}
- (UICollectionViewCell *)tableView:(UICollectionView *)tableView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
PlaceCell *cell = (PlaceCell *)[tableView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
UINib * placeCell = [UINib nibWithNibName:#"Shops" bundle:nil];
//cell = [cellLoader instantiateWithOwner:self options:nil];
NSArray *topLevelItems = [placeCell instantiateWithOwner:self options:nil];
cell = [topLevelItems objectAtIndex:0];
Place *p = [_entries objectAtIndex:indexPath.row];
cell.placeName.text = p.PName;
NSLog (#"p:%#", p.PName")
cell.placeImg.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:p.PImage]]];
return cell;
}
I went into the xib of the UICollectionViewCell (PlaceCell) and made sure that "Cell" was the reuseidentifier. And I made sure that the datasource and delegate were connected to file's owner in the collectionView.
I also noticed that when I use a custom layout instead of the flow layout (like this one: https://github.com/ShadoFlameX/PhotoCollectionView/blob/master/CollectionViewTutorial/BHPhotoAlbumLayout.m ) it doesn't give me that error... but my collectionview still isn't populated.
So I'm wondering if there's some sort of log I can run or something I can do to figure out what's going wrong. Because I've tried all the solutions I've seen and it hasn't gotten me anywhere.
When you make a cell in a xib file you should register the xib, not the class. Also, when you register either the class or xib (or make the cell in the storyboard), you don't need an if (cell==nil) clause because your cell will never be nil when you dequeue it with dequeueReusableCellWithReuseIdentifier:forIndexPath:. You should delete that clause.
So the problem is: "Switched from UITableView to UICollectionView and no valid cell is being returned." It is really a two part answer. The crux of which is every instance of UITableView...
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 50, self.view.bounds.size.width, self.view.bounds.size.height-50)];
...you want to turn into "CollectionView"
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 50, self.view.bounds.size.width, self.view.bounds.size.height-50)];
Everything that's a "row":
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
...you'll want to turn into an "item."
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
Ultimately I had to delete the following section entirely:
UINib * placeCell = [UINib nibWithNibName:#"Shops" bundle:nil];
//cell = [cellLoader instantiateWithOwner:self options:nil];
NSArray *topLevelItems = [placeCell instantiateWithOwner:self options:nil];
cell = [topLevelItems objectAtIndex:0];
My best guess is that the Nib was being loaded twice and that Xcode was complaining that the data wasn't being loaded by the original. So getting rid of that second entry got my cells loaded and populated with data. Hope this helps someone.

Implement checkbox in NSTableView in mac application

First of all, I searched for 3 days and have not found what I am looking for.
Second point, I am VERY new to Xcode programming so PLEASE keep your answer as simple and/or detailed as possible!
Inside my NSTableView I need the first column to be text followed by X number of checkbox columns with the last column to be text. The X number of columns is a variable based on the number of entries I read from a SQLite file.
My questions are:
How do I define at runtime what type and how many columns I have?
How do I know whether a checkbox value is checked or not?
How do I add rows to the tableview if I don't know the number of cells it has?
Thanks for taking the time to answer!
Best regards,
Igor
You want to create a table at runtime, and you dont know how many columns will be there!!!
Thats a big deal.
Read NSTableView documentation and you will find addTableColumn: method. in the loop go on to create colmn and dont forget to give identifier to all columns.
And over this you want to have a checkbox. Creating checkbox is not difficult either.
EDIT:
For checkbox implementation, find a project here.
Draw a checkBoxCell in the column you want to have checkbox. Or you can do it programatically.
I did it through IB.
You should create an array that will store the states for each(number of rows) checkboxes.
- (id)init {
self = [super init];
if (self) {
states=[[NSMutableArray alloc] initWithObjects:#"1", #"0", #"1", nil];
}
return self; }
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
NSLog(#"Num of rows---- %ld", [names count]);
return [names count];
}
Check for tableIdentifier having value "check".
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
if ([[tableColumn identifier] isEqualTo:#"name"]) {
return [names objectAtIndex:row];
}
else if ([[tableColumn identifier] isEqualTo:#"check"]) {
return [states objectAtIndex:row];
}
else if ([[tableColumn identifier] isEqualTo:#"states"]) {
return [states objectAtIndex:row];
}
return 0;
}
Update the value of checkbox as per on/off.
- (void)tableView:(NSTableView *)tableView setObjectValue:(id)value forTableColumn:(NSTableColumn *)column row:(NSInteger)row {
[states replaceObjectAtIndex:row withObject:value];
[tableView reloadData];
}

xcode uitableview

i have an array of objects which i am populating in a UItable one of my attributes of each object is a YES/NO value
Im using the- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { to populate my table as follows .
My code creates a table entry for each object in the array. I would like to only populate the table using objects in the array which have the "display" attribute set to YES? how do i do this?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellidentifier = #"customcell";
customcell *cell = (customcell *)[tableView dequeueReusableCellWithIdentifier:
cellidentifier];
my_details *myObj = [appDelegate.myArray objectAtIndex:indexPath.row];
// UITableViewCell cell needs creating for this UITableView row.
if (cell == nil)
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"customcell" owner:self options:nil];
for (id currentObject in topLevelObjects) {
if ([currentObject isKindOfClass:[customcell class]]) {
cell = (customcell *) currentObject;
break;
}
}
}
cell.line1.text = myObj.line1;
cell.line2.text = myObj.line2;
cell.line3.text = myObj.line3;
return cell;
}
It would be a good idea to try to filter the objects before sending them to the table for display.
You could use an NSPredicate to filter the array of objects and when an object changes it's state, the display attribute is set to yes, refilter the array and pass it to the tableview.
NSPredicate *testForTrue = [NSPredicate predicateWithFormat:#"display == YES"];
NSArray *filteredArray = [myObjectsArray filteredArrayUsingPredicate:testForTrue];
after you obtain the filteredArray you need to pass it to the tableView and tell it to reload it's data in order to refresh.
As #Sorin indicates you have to filter your table. This can be done before or during the insertion in the table. Which one is a matter of taste (and which guidelines you normally follow for programming)
a) Before
Have all data -> filter -> Have reduced set -> Display reduced table
b) During
Have all data -> count #items -> introduce in rows -> Display table
For that you have to adapt numberOfRowsInSection (pseudo code!)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
counter=0;
for each in table
if value = YES counter++
return counter;
}
In the cellForRowAtIndexPath you now have to keep track of the next line to insert, via a global variable: (pseudo code!)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
rowcounter++;
cell.textLabel.text=[selectionTableArray objectAtIndex:rowcounter];
return cell;
}

Using a different view in editing mode in a view based NSTableView

I have a NSTableView with a single NSTableCellView column that let's say, has an icon, name and an optional date.
When you edit a row, I want to replace the whole view with a simple NSTextField, and I will do some parsing to that text and extract that optional date, if present.
My question is, how would you implement this editing mechanism?
I tried returning a different view in the tableView:viewForTableColumn:row, something like:
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
BOOL isSelected = [tableView isRowSelected:row];
if (isSelected)
{
NSView *view = [tableView makeViewWithIdentifier:#"editor" owner:self];
....snip....
return view;
}
else
{
TaskView *view = [tableView makeViewWithIdentifier:#"view" owner:self];
....snip....
return view;
}
}
and then whenever the selected row changes, trying to request a refresh on that row.
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
{
NSTableView *table = [aNotification object];
NSUInteger rowIndex = [table selectedRow];
[table reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:rowIndex]
columnIndexes:[NSIndexSet indexSetWithIndex:0]];
}
It doesn't quite work, and the code feels a bit dirty.
It must be a better way of doing this, and I can't seem to find in the docs or online.

<NSInternalInconsistencyException> Invalid update: invalid number of sections

I am adding user defined text in a UItableView via a modal view controller.
The table is created as a NSMutableArray. on entering data in the modal view and tapping a Done button a Invalid update: invalid number of sections. error is generated.
I must update the array when the user enters data but not sure how to do that. I have attached the relevant code. Thanks for your advice.
//Number of sections
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; }
//Number of rows
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [listOfConjProcedures count];
}
//Loading the cells
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell.
cell.textLabel.text = [listOfConjProcedures objectAtIndex:indexPath.row];
return cell;
}
//Done button Delegate for the modal view
- (void)itemDetailViewController:(ItemDetailViewController *)controller didFinishAddingItem:(ChecklistItem *)item
{
int newRowIndex = [listOfConjProcedures indexOfObject:item];
[listOfConjProcedures addObject:item];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:newRowIndex inSection:0];
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
[self dismissViewControllerAnimated:YES completion:nil];
}
I think your problem may be here:
int newRowIndex = [listOfConjProcedures indexOfObject:item];
This wouldn't have an index unless you'd already added it to the array, but in the next line you add it to the array, so it doesn't make sense.
I think you are therefore adding a row at index path 0,NSNotFound, which will confuse the table view. Either use the count of the array as the row index, or insert your new row at the start (0,0) of the table (and at index 0 of the array).

Resources