Help Please!!, need to call different nib files for each cell.

Discussion in 'iOS Programming' started by Nekbeth, Feb 20, 2011.

  1. Nekbeth, Feb 20, 2011
    Last edited: Feb 20, 2011

    Nekbeth macrumors member

    Nekbeth

    Joined:
    Feb 20, 2011
    Location:
    Vatican City
    #1
    Hello, I'm a bit new to objective-C. I'm building a database with a property list as my data source. I have Search, index and sections working ok. Here is a look at my .plist (photo 1). My problem comes inside the "didSelectRowAtIndexPath" method, I'm trying to add different nib file for each NString (recipe details views). I read that I can't use the Switch statement because it only works with Integers, so I have try the If/else statement (photo 2) with the isEqualToString: Method.

    The result is that the compiler runs it but ignores the selection of cells, I can see the tableview with all the recipes, but I get no response after I select each cell. I'm thinking that I might need to call the Dictionary first. :confused:


    Any kind of help is well appreciated. Thank you.



    * For some reason, if I try to add a number (integer) to my .plist in order to call the nib files through the Switch statement, the App will crash each time, it won't let me have two dictionaries, just one dic, one array and many strings. So that is why I'm trying to call the nibs though the "isEqualToString: Method"
     

    Attached Files:

    • 1.jpg
      1.jpg
      File size:
      80.4 KB
      Views:
      41
    • 2.jpg
      2.jpg
      File size:
      109.1 KB
      Views:
      51
  2. dantastic macrumors 6502

    dantastic

    Joined:
    Jan 21, 2011
    #2
    Have you tried to add some NSLog messages to see what happens?

    The code you have there looks alright.

    How are you populating your array btw? just looking at the plist I'm thinking there might be something else in your array...
     
  3. Nekbeth thread starter macrumors member

    Nekbeth

    Joined:
    Feb 20, 2011
    Location:
    Vatican City
    #3

    I haven't try NSLog, I'm not sure how it would me call the nibs for the different cells.

    The array is only the letter of the recipes with several strings inside, that's it. I've seen many cases where the Array has dictionaries inside in order to have an Integer as the View and use the switch statement. (like photo 3), the plist of that method changes also (photo 4), the result is that everythings works alright. So why don't use this last code? because when I add search functions and sections it crashes all the time.

    The present proyect has the same intention, but it already has the search and sections working OK, the only difference is that It won't let me add multiple dictionaries, just (One dictionary, One array and many Strings).. therefore I'm trying to fix that DidSelectMethod: to call the Strings by it's name instead of the Number.

    I hope you can understand, It's a little confusing.. In summary I'm trying to merge the present project (which has Search and Sections working) with the previous project (which has the calling of cells to nibs working but not the Search and section).

    If you need more information, please let me know. :)
     

    Attached Files:

    • 3.jpg
      3.jpg
      File size:
      217.7 KB
      Views:
      51
    • 4.jpg
      4.jpg
      File size:
      55.7 KB
      Views:
      29
  4. Nekbeth thread starter macrumors member

    Nekbeth

    Joined:
    Feb 20, 2011
    Location:
    Vatican City
    #4
    Finally !! here is the answer :)

    If you know objective C or a bit of C.. I'm guessing this should be a piece of cake, nevertheless...not many experts take the time to point out an error to newbies like us. Anyway, I like to share this simple code so some of you don't get stuck like me for weeks ... This will help you with"pushing views from different cells". (code is in photo 1)

    Don't forget to import your controller header files into the TableView.m & connect your nib files in IB.

    Good luck and Have a nice day :D
     

    Attached Files:

    • 1.jpg
      1.jpg
      File size:
      172.3 KB
      Views:
      88
  5. dantastic macrumors 6502

    dantastic

    Joined:
    Jan 21, 2011
    #5
    Aah, I think I get it now.

    When the user selects a cell you are pushing a new view.

    The code to push the viewcontroller looks correct.

    add some NSLog messages and make sure to print out those variables as well so you know what's in them.

    The dictionary and array that you're creating you may want to look at initializing.
    Code:
    NSArray *myArray = [[NSArray alloc] initWithArray:[dictionary objectForKey:@"Whatever"]];
    
     
  6. Nekbeth, Feb 22, 2011
    Last edited: Feb 22, 2011

    Nekbeth thread starter macrumors member

    Nekbeth

    Joined:
    Feb 20, 2011
    Location:
    Vatican City
    #6

    Hi dantastic, thanks for your support. I didn't initialize a Dictionary because all the recipes were already added into the Array: "listOfRecipes" before, I initialized that Array ,is it correct? (photo 3) and I was wondering how would you add the NSlog message and print the variables in this method. I watched a tutorial about NSLog calling instance methods as integers but I'm a bit confused on how to call & print these variables on this particular example.
     

    Attached Files:

    • 3.jpg
      3.jpg
      File size:
      189.8 KB
      Views:
      38
  7. Nekbeth thread starter macrumors member

    Nekbeth

    Joined:
    Feb 20, 2011
    Location:
    Vatican City
    #7
    One Question Dantastic:

    When I open the nib files from each cell.. it takes me to a nib but not in the proper section. (For example, if I touch the first cell of the first section it takes me to the right recipe, but if I go to the next section then it start all over again with the same nib file) I'm thinking i must return the number of recipes in each section first and then initialize the Array.. do you have any idea.. how the code would change? I have something like this:

    //---check the current recipe based on the section index---
    NSString *category = [categories objectAtIndex:section];

    //---returns the recipes in that category as an array---
    NSArray *recipeSection = [recipeTitles objectForKey:category];



    I have to try to implement it in the didSelectRowAtIndexPath method, but I get either error or it crashes after selecting the same row twice.

    Thanks
     
  8. dantastic macrumors 6502

    dantastic

    Joined:
    Jan 21, 2011
    #8
    Hey,

    What I often do when I'm not sure what's going on I add
    Code:
    NSLog(@"1");
    [self function];
    NSLog(@"2");
    int i = 0;
    NSLog(@"3");
    
    Then open up the 'ol console and you will see what path your code is going down.
    If I was you I'd add pretty early in the function a
    Code:
    NSLog("Recipe: %@", [recipes objectAtIndex:indexPath.row]);
    That will let you know exactly what is in your array at that time.

    To answer your question though you must also be aware of sections.
    Your indexPath comes with a row and a section value. indexPath.row will start at 0 for every section. This is why you are only getting the correct view for the items in the first section.
    The function you have screen printed there does not take section in to consideration. You may need to (First add some NSLoggs to observe this behaviour.)
    Code:
    NSLog(@"Index Path Section: %i, Row: %i", indexPath.section, indexPath.row);
    
     
  9. Nekbeth, Feb 24, 2011
    Last edited: Feb 24, 2011

    Nekbeth thread starter macrumors member

    Nekbeth

    Joined:
    Feb 20, 2011
    Location:
    Vatican City
    #9
    Hi dantastic, I'm trying to add the NSLog messages like you pointed out but I always get a warning or error. Where do you add them exactly?, inside the method "DidSelectRowAtindexPath"? and excuse me for ignoring something so important, but how would you code the NSLog for the recipes array in the example I gave? Do you print them so they appear in the console? In some tutorials, they first declare an action called "print" and use it on the NSLog. (Photo 4 shows the warning of NSLogs)

    I would really like to know what's going on inside the console in order to get the correct view for the items in each section without starting at 0.

    So far in the numberOfRowsInSection: Method, I have the following:

    Code:
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        
    	// Return the number of rows in the section.
    	if (isSearchOn) { 
    		return [searchResult count];
    	} 
    	else {
    	
    	//---check the current category based on the section index--- 
    	NSString *category = [categories objectAtIndex:section];
    	
    	//---returns the recipes in that category as an array---
    	NSArray *recipeSection = [recipeTitles objectForKey:category];
        
    	//---return the number of recipes for that category as the number of rows in that // section ---
    	return [recipeSection count];
    		
    	}
    }
    	

    I wonder how to call those sections, either by string name or number like some people did with this example:

    Code:
    - else if (indexPath.section == 1 & indexPath.row == 0){ FaceBook *nextController = [[FaceBook alloc] initWithNibName:@"FaceBook" bundle:nil]; [self.navigationController pushViewController:nextController animated:YES];  



    Thanks :)
     

    Attached Files:

    • 4.jpg
      4.jpg
      File size:
      221.9 KB
      Views:
      36
  10. Nekbeth, Feb 24, 2011
    Last edited: Feb 24, 2011

    Nekbeth thread starter macrumors member

    Nekbeth

    Joined:
    Feb 20, 2011
    Location:
    Vatican City
    #10
    Interesting :).. this seems to work

    After testing out some example codes and thinking a bit logical, I finally found the following code to work by sections and cells selected, this time I use Integers to find the section and cell in order to call the nib.

    Thanks dantastic,

    * I still don't know why I can't get the NSLog to show anything. I have try step by step follow up easy tutorials but my console does not show the logs. Maybe I have to enable it or something.
     
  11. dantastic macrumors 6502

    dantastic

    Joined:
    Jan 21, 2011
    #11
    Glad you got it going.

    NSLog is always there, it's stdout.

    When you are saying console, you mean in xcode > Run > Console?

    The only think I can think of is that you've the Terminal open, that won't show a thing.
     
  12. Nekbeth thread starter macrumors member

    Nekbeth

    Joined:
    Feb 20, 2011
    Location:
    Vatican City
    #12
    Yes, the debugger console not the terminal. I must be doing something wrong in the NSLog code.. but anyway. I got the sections going, so thats good. :)

    Recipes are ready to go, I'm working on the Categories TabBar now, theres already a navigation with tableview inside there too. (separate from Recipes TableView nib). I'm having a bit of trouble showing up the icon images next to the text inside the cell. I can only do it for the first tableView because I call the images through exact rows, that's seem to work ok.. but the problem is that the same image stays the same when I push the view to the next subcategory. (I know it's because I'm calling only the row and the image stays on the row)

    In my dictionary, I have for example: 5 categories of Cakes > 5 subcategories of each Cake (for example Tea Cakes) > 5 recipes of Tea Cakes pushing a Detail View each (nib file)

    The code that I'm using is the following:
    Code:
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        
        static NSString *CellIdentifier = @"Cell";
    	
    	CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    	if (cell == nil) {
    		cell = [[[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    	}
    	// Configure the cell...
    	NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row];
    	cell.textLabel.text = [dictionary objectForKey:@"Title"];
    	
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    	
    	
    	// Set up the cell…
    	if (indexPath.row == 0) {
    		
    			
    			cell.myImageView.image = [UIImage imageNamed:@"Cheese Cake.jpg"];
    	}
    	else if (indexPath.row == 1) {
    	
      			
    			cell.myImageView.image = [UIImage imageNamed:@"Chocolate Cake.jpg"];
    	}
           else if (indexPath.row == 2) {
    		
    		
    		    cell.myImageView.image = [UIImage imageNamed:@"Carrot Cake.jpg"];
    	}
    	
        return cell;
    }
    
    As you can see, I call the images only through indexPath.row, I'm trying to call the Value Name of the String in the dictionary (not the Key) so each cell can have an image and change even if I push the view to another category. Something like this (I know this is wrong):
    Code:
     if ([[NSString is EqualToString: @"Decorated Cake"]) {
    }   
     
    "Maybe initialize the Dictionary first and create a local variable to use inside the If/else statement, I don't know.. I have try many ways and every time I get an error or warning. Any help with that code would be awesome :D


    By the way, is there a way to add images to cells using Interface Builder? and if so, would you recommend doing it there?

    Thanks, good day
     
  13. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #13
    When you build the dictionary add the name of the image to it. You can then

    Code:
    NSString* imageName = [dictionary objectForKey:@"ImageNameKey"];
    cell.myImageView.image = [UIImage imageNamed:imageName];
    
    BTW, UITableViewCell initWithFrame is deprecated. You should use initWithStyle.

    Put as much state about each row in your data model so you can make your code more simple.
     
  14. Nekbeth thread starter macrumors member

    Nekbeth

    Joined:
    Feb 20, 2011
    Location:
    Vatican City
    #14
    Hello PhoneyDeveloper, thanks for your help.. I was able to do it with this code:
    Code:
    	// Set up the cell…
    	if ([dictionary objectForKey:@"Cakes"]) {
    		
    		cell.primaryLabel.text = @"Cakes";
    		cell.secondaryLabel.text = @"";
    		cell.myImageView.image = [UIImage imageNamed:@"Cheese Cake.jpg"];
    	}
    	
    	else if ([dictionary objectForKey:@"Cheese Cake"]) {
    		
    	    cell.primaryLabel.text = @"Cheese Cake";
    		cell.secondaryLabel.text = @"";
    		cell.myImageView.image = [UIImage imageNamed:@"Cheese Cake.jpg"];
    	}
    	else if ([dictionary objectForKey:@"Chocolate Cake"]) {
    	
    		cell.primaryLabel.text = @"Chocolate Cake";
    		cell.secondaryLabel.text = @"";
    		cell.myImageView.image = [UIImage imageNamed:@"Chocolate Cake.jpg"];
    	}
    	
    	else if ([dictionary objectForKey:@"Tarts"]) {
    		
    		cell.primaryLabel.text = @"Tarts";
    		cell.secondaryLabel.text = @"";
    		cell.myImageView.image = [UIImage imageNamed:@"Lemon Tart.jpg"];
    	}
    	
        
        return cell;
    }
    It's from an imported custom cell. If you see an error or something wrong, please let me know, I'll be glad to learn or clean up the code.
     
  15. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #15
    The way you're doing it doesn't scale well. What if you had 100 rows, or 50,000, or if you downloaded new data from a web site?

    Best is if all of the row details are in the rowDictionary. Then you read all the details to display in the row from the dictionary and display them.
     
  16. Nekbeth thread starter macrumors member

    Nekbeth

    Joined:
    Feb 20, 2011
    Location:
    Vatican City
    #16

    I know what you mean and that's how I first wanted the database to be. I would love to handle everything from the Dictionary but I got stuck with the following code:

    Code:
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        
        static NSString *CellIdentifier = @"Cell";
    	
    	CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    	if (cell == nil) {
    		cell = [[[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    	}
    	
    	// Configure the cell...
    	NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row];
    	cell.textLabel.text = [dictionary objectForKey:@"Title"];
    	
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    
    	
    	
    	// Set up the cell…
    	
    	
        
        return cell;
    }
    
    I called the Title for key but doing so, I always get the same image in all cells.. about the code for images that you posted before :
    Code:
    NSString* imageName = [dictionary objectForKey:@"ImageNameKey"];
    cell.myImageView.image = [UIImage imageNamed:imageName];
    How and where do you implement that code, do you use if/else? switch? and what do you mean by "When you build the dictionary add the name of the image to it", because I have this code using the dictionary:
    Code:
    NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row];
    	cell.textLabel.text = [dictionary objectForKey:@"Title"];
    If I add the name of the image instead of @"Title" it will only call that String. As you can see I'm confused, I'll appreciate if you can show me how by example.

    Thank you,

    * I have attached the .plist, so you have a notion of the dictionary
     

    Attached Files:

  17. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #17
    OK, it appears that your data model is a plist file. Each row is represented by a dictionary. Each row dictionary has in it a Title and maybe some other stuff. In addition to the Title you should add the imageName. Then the code I showed would work. You put the code I showed where you have "Set up the cell...".

    This allows to avoid any "if" or "switch" logic. Each row has a title and an image. You just read it and set the values for the cell.

    This is sometimes called "data driven" UI. The data has the info that's meant to be displayed.

    Honestly, your plist seems to have to many levels. Usually they are an array of dictionaries, for a non-sectioned table. Or an array of arrays of dictionaries for a sectioned table.
     
  18. Nekbeth thread starter macrumors member

    Nekbeth

    Joined:
    Feb 20, 2011
    Location:
    Vatican City
    #18
    Indeed, I'm planning on shortening my plist. It has dictionaries inside because I'm using a Navigation controller and after two or three levels, I will push a nib file (detail view). It may also have sections too. Well so far, I follow your comments and I was able to call the imageNameKey (photo below). It's funny, when I think I'm ready to go and fill my recipes.. something always comes up :p, that's expected because I'm sort of new to iPhone development. Anyway.. now I'm facing image overlapping with the Title text (photo 2 below). It would be easy to just move ahead the text on the dictionary value where all the names are and set the background color to transparent in IB, but if I do that, when I select the row.. its set to show the Title of the "CurrentTitle" too in the nav controller:
    Code:
    self.navigationItem.title = @"Categories";
    	}
    	else
    		self.navigationItem.title = CurrentTitle;
    So what happens is that the Title that I moved a bit to the right (in order to show avoid overlapping the image), moves also the Title for the Nav controller and it looks awkward.

    There might be a small code to adjust the Title of the row to be set in the middle without moving the Navigation Title (always centered).. at least I hope so :rolleyes:
     

    Attached Files:

  19. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #19
    The position of the text in the cell isn't related to the position of the text in the navbar. The position of the text in the cell depends on how your custom cell is implemented.

    Code:
    self.title = @"Categories";
    is all that's required for the title of the navbar to be set.
     
  20. Nekbeth, Feb 26, 2011
    Last edited: Feb 26, 2011

    Nekbeth thread starter macrumors member

    Nekbeth

    Joined:
    Feb 20, 2011
    Location:
    Vatican City
    #20
    Hi PhoneyDeveloper, what you say is true, "Categories Title" is not effected by the cell, but if I select the cell and pushes me to another view..then it is effected because of the code i showed you. Even if I code:
    Code:
    self.title = @"Categories";
    	}
    	else
    		self.navigationItem.title = CurrentTitle;
    The Nav still takes the Title from the current recipe Title in the .plist lower level. I could change the cell inside CustomCell.m file but then I had to erase all of the Titles from the .plist and use the Titles from the custom cell. By doing so It will take more coding and it takes away the "data driven" UI that you mention.. but if there is not choice I'll do it. I posted some photos so you have a better look.
     

    Attached Files:

  21. Nekbeth thread starter macrumors member

    Nekbeth

    Joined:
    Feb 20, 2011
    Location:
    Vatican City
    #21
    This piece of code worked for me:
    Code:
    NSString* imageName = [dictionary objectForKey:@"ImageNameKey"];
    	cell.myImageView.image = [UIImage imageNamed:imageName];
    	cell.primaryLabel.text = [dictionary valueForKey:@"Title"];
    I just called the primaryLabel UILabel from the customCell to be the Title text of the dictionary. The result was that it position the text right were I wanted (after the image) without leaving the .plist data source. :)
     

Share This Page