TableViewController to 2nd level ViewController - objective-c

I have a very specific problem. I am very new to Xcode, but so far I was able to make an app with tab bar controller, where 1 of the tab controllers is tableviewcontroller. I have no problem displaying table cells in tableviewcontroller and even clicking anyone of them segueing to detailviewcontroller where table cells have extensive info, but my problem is when I am trying to segue my way even further, by clicking menu button, where I want a label and an image of a menu to show. I am getting a blank screen. I can't even see a title, not even talking about pushing through an image.
I assume problem is with pushing through the info through a level.
Here is TableViewController.h:
#import <UIKit/UIKit.h>
#interface TableViewController1 : UITableViewController
#property (nonatomic, strong) NSArray *Menus;
#property (nonatomic, strong) NSArray *Images;
#property (nonatomic, strong) NSArray *Title;
#property (nonatomic, strong) NSArray *Description;
#end
And TableViewController.m:
#import "TableViewController1.h"
#import "TableCell1.h"
#import "DetailViewController.h"
#import "MenuViewController.h"
#interface TableViewController1 ()
#end
#implementation TableViewController1
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
self.tableView.separatorColor = [UIColor colorWithRed:0/255.0 green:181/255.0 blue:0/255.0 alpha:0.5];
UIBarButtonItem *NewBackButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStyleBordered target:nil action:nil];
[[self navigationItem] setBackBarButtonItem:NewBackButton];
_Title = #[#"Velvet Sport Villa",
#"GQ",
#"29",
#"Noodles",
#"La Roof",
#"Borgo Antico",
#"Vertalet",
#"Balcon",
#"Parmigiano",];
_Description = #[#"The New Great Place",
#"Want to feel some luxury",
#"The Old Good Place",
#"Food is amazing here",
#"Too expensive",
#"Royal place",
#"Before party or After party",
#"Great place, great deserts",
#"The first place in town of that level",];
_Images = #[#"Velvet.jpg",
#"GQ.jpg",
#"29.jpg",
#"Noodles.jpg",
#"La Roof.jpg",
#"Borgo Antico.jpg",
#"Vertalet.jpg",
#"Balcon.jpg",
#"Parmigiano.jpg",];
_Menus = #[#"Velvet Menu.jpg",
#"GQ Menu.jpg",
#"29 Menu.jpg",
#"Noodles Menu.jpg",
#"La Roof Menu.jpg",
#"Borgo Antico Menu.jpg",
#"Vertalet Menu.jpg",
#"Balcon Menu.jpg",
#"Parmigiano Menu.jpg",];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return _Title.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TableCell1";
TableCell1 *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
int row = [indexPath row];
cell.TitleLabel.text = _Title[row];
cell.DescriptionLabel.text = _Description[row];
cell.ThumbImage.image = [UIImage imageNamed:_Images[row]];
return cell;
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowDetails"])
{
DetailViewController *detailviewcontroller = [segue destinationViewController];
NSIndexPath *myInderPath = [self.tableView indexPathForSelectedRow];
int row = [myInderPath row];
detailviewcontroller.DetailModal = #[_Title[row],_Description[row],_Images[row],_Menus[row]];
}
if ([[segue identifier] isEqualToString:#"MenuDetails"])
{
MenuViewController *menuviewcontroller = [segue destinationViewController];
NSIndexPath *myInderPath = [self.tableView indexPathForSelectedRow];
int row = [myInderPath row];
menuviewcontroller.MenuModal = #[_Title[row],_Menus[row]];
}
}
#end
TableCell1.h
#import <UIKit/UIKit.h>
#interface TableCell1 : UITableViewCell
#property(strong,nonatomic) IBOutlet UILabel *TitleLabel;
#property(strong,nonatomic) IBOutlet UILabel *DescriptionLabel;
#property(strong,nonatomic) IBOutlet UIImageView *ThumbImage;
#end
TableCell1.m
#import "TableCell1.h"
#implementation TableCell1
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
DetailViewController.h
#import <UIKit/UIKit.h>
#interface DetailViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *Cuisine;
#property (weak, nonatomic) IBOutlet UILabel *Price;
#property (weak, nonatomic) IBOutlet UILabel *Decor;
#property (weak, nonatomic) IBOutlet UILabel *Service;
#property(strong,nonatomic) IBOutlet UILabel *TitleLabel;
#property(strong,nonatomic) IBOutlet UILabel *DescriptionLabel;
#property(strong,nonatomic) IBOutlet UIImageView *ThumbImage;
#property(strong,nonatomic) NSArray *DetailModal;
#end
DetailViewController.m
#import "DetailViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_TitleLabel.text = _DetailModal[0];
_DescriptionLabel.text = _DetailModal[1];
_ThumbImage.image = [UIImage imageNamed:_DetailModal[2]];
self.navigationItem.title = _DetailModal[0];
if ([_TitleLabel.text isEqualToString:#"Velvet Sport Villa"])
{
_Cuisine.text = #"German/American";
_Price.text = #"Above average";
_Decor.text = #"Great. Sporty, but cozy";
_Service.text = #"Exceptional";
}
if ([_TitleLabel.text isEqualToString:#"GQ"])
{
_Cuisine.text = #"Italian/English";
_Price.text = #"Above average";
_Decor.text = #"Exceptional";
_Service.text = #"Average";
}
if ([_TitleLabel.text isEqualToString:#"29"])
{
_Cuisine.text = #"Japanese/Italian";
_Price.text = #"Average";
_Decor.text = #"Cozy";
_Service.text = #"So So";
}
if ([_TitleLabel.text isEqualToString:#"Noodles"])
{
_Cuisine.text = #"Chinese/Italian";
_Price.text = #"Average";
_Decor.text = #"Interesting";
_Service.text = #"Groomy, but fast";
}
if ([_TitleLabel.text isEqualToString:#"La Roof"])
{
_Cuisine.text = #"American/Italian";
_Price.text = #"Very High";
_Decor.text = #"OK";
_Service.text = #"OK";
}
if ([_TitleLabel.text isEqualToString:#"Borgo Antico"])
{
_Cuisine.text = #"Medeterranean";
_Price.text = #"Above average";
_Decor.text = #"Marvelous";
_Service.text = #"Not Bad";
}
if ([_TitleLabel.text isEqualToString:#"Vertalet"])
{
_Cuisine.text = #"All";
_Price.text = #"Above average";
_Decor.text = #"Fine, nothing special";
_Service.text = #"Not Bad";
}
if ([_TitleLabel.text isEqualToString:#"Balcon"])
{
_Cuisine.text = #"Italian/Coffee";
_Price.text = #"Above Average";
_Decor.text = #"Modern";
_Service.text = #"Best";
}
if ([_TitleLabel.text isEqualToString:#"Parmigiano"])
{
_Cuisine.text = #"Italian";
_Price.text = #"Above Average";
_Decor.text = #"Stunning";
_Service.text = #"Annoying";
}
}
#end
Finally MenuViewController.h
#import <UIKit/UIKit.h>
#interface MenuViewController : UIViewController
#property(strong,nonatomic) IBOutlet UILabel *TitleLabel;
#property (strong,nonatomic) IBOutlet UIImageView *MenuImage;
#property(strong,nonatomic) NSArray *MenuModal;
#end
And Lastly MenuViewController.m
#import "MenuViewController.h"
#interface MenuViewController ()
#end
#implementation MenuViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.title = _MenuModal[0];
_TitleLabel.text = _MenuModal[0];
_MenuImage.image = [UIImage imageNamed:_MenuModal[3]];
}
#end

Related

Illegal NSTableView data source - what did I wrong?

I have an app, where I added simple images (posters) with movie names. But after run, I can see only empty table and an error in console:
Illegal NSTableView data source (). Must implement numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:
Now, in my .xib file I have Table View with dataSource and delegate linked to the File's Owner. Here's the code:
MasterViewController.m
#import "MasterViewController.h"
#import "NSObject+IntengineMovieData.h"
#import "NSObject+IntengineMovieDoc.h"
#interface MasterViewController ()
#end
#implementation MasterViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do view setup here.
}
- (NSView *)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
NSTableCellView *cellView = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
if([tableColumn.identifier isEqualToString:#"MoviesColumn"]) {
IntengineMovieDoc *movieDoc = [self.movies objectAtIndex:row];
cellView.imageView.image = movieDoc.thumbImage;
cellView.textField.stringValue = movieDoc.data.title;
return cellView;
}
return cellView;
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return [self.movies count];
}
#end
What that problem means and how can I fix it in my case?
EDIT 1: I have MasterViewController.xib as my Main Interface. I loaded it by this:
AppDelegate.m
#import "AppDelegate.h"
#import "NSObject+IntengineMovieDoc.h"
#include "MasterViewController.h"
#interface AppDelegate ()
#property (nonatomic, strong) IBOutlet MasterViewController *masterViewController;
#property (assign) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.masterViewController = [[MasterViewController alloc]
initWithNibName:#"MasterViewController" bundle:nil];
IntengineMovieDoc *movie1 = [[IntengineMovieDoc alloc] initWithTitle:#"The Godfather" rating:5 thumbImage:[NSImage imageNamed:#"TheGodfatherThumb.jpg"] fullImage:[NSImage imageNamed:#"TheGodfather.jpg"]];
IntengineMovieDoc *movie2 = [[IntengineMovieDoc alloc] initWithTitle:#"Tree of Life" rating:4 thumbImage:[NSImage imageNamed:#"TreeOfLifeThumb.jpg"] fullImage:[NSImage imageNamed:#"TreeOfLife.jpg"]];
IntengineMovieDoc *movie3 = [[IntengineMovieDoc alloc] initWithTitle:#"Taxi Driver" rating:5 thumbImage:[NSImage imageNamed:#"TaxiDriverThumb.jpg"] fullImage:[NSImage imageNamed:#"TaxiDriver.jpg"]];
NSMutableArray *movies = [NSMutableArray arrayWithObjects: movie1, movie2, movie3, nil];
self.masterViewController.movies = movies;
[self.window.contentView addSubview:self.masterViewController.view];
self.masterViewController.view.frame = ((NSView*)self.window.contentView).bounds;
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
#end

Best Pattern for multiple Popovers in Storyboard

I am writing an iPad application which will have several buttons that when clicked open a popover to a tableview. The user will choose a value, and the popover will be dismissed and the button't title will change.
I got this working with one Popover, and then wanted to add another. I want to write some good, clean reusable code.
My big hangup is with delegates. How many should there be? Should each popover have its own.
Root View Controller Header
#import <UIKit/UIKit.h>
#import "PopViewController1.h"
#import "PopViewController2.h"
#interface RootViewController : UIViewController <PopViewControllerDelegate,UIPopoverControllerDelegate>
// Properties for accessing the popover and its viewcontroller (1)
#property (strong, nonatomic) IBOutlet UIButton *btnOpenPopover1;
#property (strong, nonatomic) UIStoryboardPopoverSegue *pvcSegue1;
#property (strong, nonatomic) PopViewController1 *pvc1;
// Properties for accessing the popover and its viewcontroller (2)
#property (strong, nonatomic) IBOutlet UIButton *btnOpenPopover2;
#property (strong, nonatomic) UIStoryboardPopoverSegue *pvcSegue2;
#property (strong, nonatomic) PopViewController2 *pvc2;
#end
Root View Controller Method
#import "RootViewController.h"
#interface RootViewController ()
#end
#implementation RootViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[self setBtnOpenPopover1:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"segPop1"]) {
_pvcSegue1 = (UIStoryboardPopoverSegue *)segue;
_pvc1 = [segue destinationViewController];
[_pvc1 setDelegate:self];
} else ([[segue identifier] isEqualToString:#"segPop2"]); {
_pvcSegue2 = (UIStoryboardPopoverSegue *)segue;
_pvc2 = [segue destinationViewController];
//[_pvc2 setDelegate:self];
}
}
// PopViewControllerDelegate callback function
- (void)dismissPop:(NSString *)value {
[_btnOpenPopover1 setTitle:value forState:UIControlStateNormal];
[[_pvcSegue1 popoverController] dismissPopoverAnimated: YES]; // dismiss the popover
}
#end
PopViewController1.h
#import <UIKit/UIKit.h>
#protocol PopViewControllerDelegate;
#interface PopViewController1 : UITableViewController
#property (weak) id <PopViewControllerDelegate> delegate;
#property (strong, nonatomic) NSString *strPassedValue;
#property (nonatomic, strong) NSMutableArray *importantChoices;
#end
#protocol PopViewControllerDelegate <NSObject>
#required
- (void)dismissPop:(NSString *)value;
#end
PopViewController1 Method
#import "PopViewController1.h"
#interface PopViewController1 ()
#end
#implementation PopViewController1
- (id)initWithCoder:(NSCoder *)aDecoder
{
//Popover Choices
_importantChoices = [NSMutableArray array];
[_importantChoices addObject:#"Extremely Important"];
[_importantChoices addObject:#"Very Important"];
[_importantChoices addObject:#"Somewhat Important"];
[_importantChoices addObject:#"Not Very Important"];
[_importantChoices addObject:#"Not At All Important"];
self.clearsSelectionOnViewWillAppear = NO;
NSInteger rowsCount = [_importantChoices count];
NSInteger singleRowHeight = [self.tableView.delegate tableView:self.tableView
heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
NSInteger totalRowsHeight = rowsCount * singleRowHeight;
//Calculate how wide the view should be by finding how
//wide each string is expected to be
CGFloat largestLabelWidth = 0;
for (NSString *colorName in _importantChoices) {
//Checks size of text using the default font for UITableViewCell's textLabel.
CGSize labelSize = [colorName sizeWithFont:[UIFont boldSystemFontOfSize:20.0f]];
if (labelSize.width > largestLabelWidth) {
largestLabelWidth = labelSize.width;
}
}
//Add a little padding to the width
CGFloat popoverWidth = largestLabelWidth + 100;
//Set the property to tell the popover container how big this view will be.
self.contentSizeForViewInPopover = CGSizeMake(popoverWidth, totalRowsHeight);
return self;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Uncomment the following line to preserve selection between presentations.
//self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void)viewWillAppear: (BOOL)animated
{
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [_importantChoices count];}
- (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];
}
cell.textLabel.text = [_importantChoices objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
_strPassedValue = [_importantChoices objectAtIndex:indexPath.row];
[_delegate dismissPop:_strPassedValue];
}
#end
PopViewController2 Header
#import <UIKit/UIKit.h>
#protocol PopViewControllerDelegate;
#interface PopViewController2 : UITableViewController
#property (weak) id <PopViewControllerDelegate> delegate;
#property (strong, nonatomic) NSString *strPassedValue2;
#property (nonatomic, strong) NSMutableArray *importantChoices2;
#end
#protocol PopViewControllerDelegate <NSObject>
#required
- (void)dismissPop2:(NSString *)value;
#end
PopViewController2 Method
import "PopViewController2.h"
#interface PopViewController2 ()
#end
#implementation PopViewController2
- (id)initWithCoder:(NSCoder *)aDecoder
{
//Popover Choices
_importantChoices = [NSMutableArray array];
[_importantChoices addObject:#"Extremely Important"];
[_importantChoices addObject:#"Very Important"];
[_importantChoices addObject:#"Somewhat Important"];
[_importantChoices addObject:#"Not Very Important"];
[_importantChoices addObject:#"Not At All Important"];
self.clearsSelectionOnViewWillAppear = NO;
NSInteger rowsCount = [_importantChoices count];
NSInteger singleRowHeight = [self.tableView.delegate tableView:self.tableView
heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
NSInteger totalRowsHeight = rowsCount * singleRowHeight;
//Calculate how wide the view should be by finding how
//wide each string is expected to be
CGFloat largestLabelWidth = 0;
for (NSString *colorName in _importantChoices) {
//Checks size of text using the default font for UITableViewCell's textLabel.
CGSize labelSize = [colorName sizeWithFont:[UIFont boldSystemFontOfSize:20.0f]];
if (labelSize.width > largestLabelWidth) {
largestLabelWidth = labelSize.width;
}
}
//Add a little padding to the width
CGFloat popoverWidth = largestLabelWidth + 100;
//Set the property to tell the popover container how big this view will be.
self.contentSizeForViewInPopover = CGSizeMake(popoverWidth, totalRowsHeight);
return self;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Uncomment the following line to preserve selection between presentations.
//self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void)viewWillAppear: (BOOL)animated
{
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [_importantChoices count];}
- (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];
}
cell.textLabel.text = [_importantChoices objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
_strPassedValue = [_importantChoices objectAtIndex:indexPath.row];
[_delegate dismissPop:_strPassedValue];
}
#end
Any help or suggestions would be greatly appreciated!!!
Bryan
For reusable code, you only want one version of PopViewController. Your two versions look identical, so get rid of one. In InterfaceBuilder, set your buttons to all segue to a single PopViewController. Root View Controller, then, looks like this:
#property (strong, nonatomic) IBOutlet UIButton *btnOpenPopover1;
#property (strong, nonatomic) IBOutlet UIButton *btnOpenPopover2;
In prepareForSegue:, rather than segue to one version or another of PopViewController, just segue to your single version. Add a property to Root View Controller, to keep track of it (this replaces pvc1 and pvc2):
#property (strong, nonatomic) PopViewController* currentPopoverController;
You also need to keep track of which button is being edited, so add a property to your Root View Controller for that (note the weak reference):
#property (weak, nonatomic) IBOutlet UIButton* currentButton;
Set both of these in prepareForSegue:, so it looks like this:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
currentPopoverController = [segue destinationViewController];
[currentPopoverController setDelegate:self];
currentButton = (UIButton*) sender;
}
Now, you only need one delegate that looks like this:
- (void)dismissPop:(NSString *)value {
[currentButton setTitle:value forState:UIControlStateNormal];
[currentPopoverController dismissPopoverAnimated:YES];
}
I figured this out.
I needed to put in my segue in the h file, set that to the segue title, and then I added the segue property to the prepareForSegue method:
_segPopViewController = (UIStoryboardPopoverSegue *)segue;
Finally in the delegate I was able to put in this line:
[[_segPopViewController popoverController] dismissPopoverAnimated: YES];
And success!
Kudos to the original poster - you helped me a ton! I wish I could up vote you more than one!!!
Bryan

filterContentForSearchText and shouldReloadTableForSearchString not called (UITableView & UISearchBar)

I'd like to implement an incremental search of words.
I implemented like below, but filterContentForSearchText and shouldReloadTableForSearchString methods are not called. Why?
WordsIndexViewController.h
#import <UIKit/UIKit.h>
#interface WordsIndexViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UISearchDisplayDelegate, UISearchBarDelegate>
#end
WordsIndexViewController.m
#import "WordsIndexViewController.h"
#import "WordsShowViewController.h"
#import "Word.h"
#interface WordsIndexViewController ()
#property (strong, nonatomic) UITableView *tableView;
#property (strong, nonatomic) NSArray *words;
#property (strong, nonatomic) NSMutableArray *searchedWords;
#end
#implementation WordsIndexViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_words = [[app models] objectForKey:#"words"];
_searchedWords = [NSMutableArray arrayWithArray:#[]];
UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 480) style:UITableViewStylePlain];
tableView.delegate = self;
tableView.dataSource = self;
_tableView = tableView;
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];
searchBar.delegate = self; // needed?
[searchBar sizeToFit]; // needed?
UISearchDisplayController *searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
searchDisplayController.delegate = self;
searchDisplayController.searchResultsDelegate = self;
searchDisplayController.searchResultsDataSource = self;
_tableView.tableHeaderView = searchBar;
[self.view addSubview:_tableView];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - related to UITableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"START numberOfRowsInSection");
NSArray *words = nil;
if (tableView == self.searchDisplayController.searchResultsTableView) {
words = _searchedWords;
} else {
words = _words;
}
return [words count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"START cellForRowAtIndexPath");
NSArray *words = nil;
if (tableView == self.searchDisplayController.searchResultsTableView) {
words = _searchedWords;
} else {
words = _words;
}
UITableViewCell *cell = [[UITableViewCell alloc] init];
Word *word = words[indexPath.row];
cell.textLabel.text = word.spelling;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *words = nil;
if (tableView == self.searchDisplayController.searchResultsTableView) {
words = _searchedWords;
} else {
words = _words;
}
WordsShowViewController *controller = [[WordsShowViewController alloc] initWithNibName:#"ViewController" bundle:nil];
controller.word = (Word *)words[indexPath.row];
[self.navigationController pushViewController:controller animated:YES];
}
#pragma mark - related to Search Bar
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
NSLog(#"Query: %#", searchString); // NOT CALLED...
[self filterContentForSearchText:searchString
scope:[
[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]
]
];
return YES;
}
- (void)filterContentForSearchText:(NSString*)searchString scope:(NSString*)scope {
NSLog(#"START filterContentForSearchText"); // NOT CALLED...
[_searchedWords removeAllObjects];
for(Word *word in _words) {
NSRange range = [word.spelling rangeOfString:searchString options:NSCaseInsensitiveSearch];
if(range.length > 0) {
[_searchedWords addObject:word];
}
}
}
#end
Word.h
#import <Foundation/Foundation.h>
#interface Word : NSObject
#property (strong, nonatomic) NSString *identifier;
#property (strong, nonatomic) NSString *spelling;
- (id)initWith:(NSString *)spelling;
#end
Word.m
#import "Word.h"
#implementation Word
- (id)initWith:(NSString *)spelling {
self = [super init];
if (!self) {
return nil;
}
CFUUIDRef uuid = CFUUIDCreate(NULL);
_identifier = (NSString *)CFBridgingRelease(CFUUIDCreateString(NULL, uuid));
CFRelease(uuid);
_spelling = spelling;
return self;
}
#end
Regards,
Finally, I solved the question myself.
To solve it, I called shouldReloadTableForSearchString in textDidChange then the incremental search worked. A diff belows:
WordsIndexViewController.m
## -16,6 +16,7 ##
#property (strong, nonatomic) NSArray *words;
#property (strong, nonatomic) NSMutableArray *searchedWords;
+#property (strong, nonatomic) UISearchDisplayController *displayController;
#end
## -52,6 +53,7 ##
searchDisplayController.searchResultsDelegate = self;
searchDisplayController.searchResultsDataSource = self;
_tableView.tableHeaderView = searchBar;
+ _displayController = searchDisplayController;
[self.view addSubview:_tableView];
}
## -132,5 +134,9 ##
}
}
}
+- (void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *) searchText {
+ [self searchDisplayController:_displayController shouldReloadTableForSearchString:searchText];
+}
#end
Thanks,
Make sure you create an iVar for the UISearchDisplayController in your header file.
If you create an UISearchDisplayController using:
UISearchDisplayController* searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchField contentsController:self];
it will get released by ARC, it will not call any delegate methods and when you'll call self.searchDisplayController (the UIViewController's property) it will be nil.
So, the fix is:
In your header (.h) file:
#interface MenuViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, UISearchDisplayDelegate> {
UISearchDisplayController* searchDisplayController;
UISearchBar *searchField;
UITableView* tableView;
NSArray* searchResults;
}
and in the implementation (.m) file:
searchField = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 49)];
searchField.delegate = self;
searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchField contentsController:self];
searchDisplayController.delegate = self;
searchDisplayController.searchResultsDataSource = self;
searchDisplayController.searchResultsDelegate = self;
tableView.tableHeaderView = searchField;
tableView.contentOffset = CGPointMake(0, searchField.frame.size.height);
When implemented like that, you can call both self.searchDisplayController and searchDisplayController in the rest of your code.

Why Isn't My UITextField Wrapper Being Displayed In UITableViewCell?

The issue is that my UITextField wrapper class isn't getting the UITextField to appear within a UITableViewCell (however, a regular UITextField view works just fine):
Here is my custom UITextField:
Header:
#import <UIKit/UIKit.h>
#protocol TUTextFieldDelegate <NSObject>
- (BOOL)textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string;
- (BOOL)textFieldShouldClear:(UITextField *)textField;
- (void)textFieldDidBeginEditing:(UITextField *)textField;
- (void)textFieldDidEndEditing:(UITextField *)textField;
#end
#interface TUTextField : UIControl <UITextFieldDelegate>
#property (nonatomic, assign) BOOL fixedDecimalPoint;
#property (nonatomic, assign) id <TUTextFieldDelegate>delegate;
#property (nonatomic, assign) UIKeyboardType keyboardType;
#property (nonatomic, strong) NSString *placeholder;
#property (nonatomic, assign) UITextBorderStyle borderStyle;
#property (nonatomic, assign) BOOL adjustsFontSizeToFitWidth;
#property (nonatomic, assign) UITextFieldViewMode clearButtonMode;
#property (nonatomic, strong) NSString *text;
- (id)initWithTextField:(UITextField *)textField;
- (id)initWithFrame:(CGRect)frame;
#end
Implementation:
#import "TUTextField.h"
#interface TUTextField ()
#property (nonatomic, strong) UITextField *textField;
#end
#implementation TUTextField
- (id)initWithTextField:(UITextField *)textField
{
self = [super initWithFrame:textField.frame];
if (self) {
self.textField = textField;
_textField.delegate = self;
_fixedDecimalPoint = NO;
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.textField = [[UITextField alloc] initWithFrame:frame];
_textField.delegate = self;
[self addSubview:_textField];
_fixedDecimalPoint = NO;
}
return self;
}
- (void)setKeyboardType:(UIKeyboardType)keyboardType {
_textField.keyboardType = keyboardType;
}
- (void)setPlaceholder:(NSString *)placeholder {
_textField.placeholder = placeholder;
}
- (void)setBorderStyle:(UITextBorderStyle)borderStyle {
_textField.borderStyle = borderStyle;
}
-(void)setAdjustsFontSizeToFitWidth:(BOOL)adjustsFontSizeToFitWidth {
_textField.adjustsFontSizeToFitWidth = adjustsFontSizeToFitWidth;
}
-(void)setClearButtonMode:(UITextFieldViewMode)clearButtonMode {
_textField.clearButtonMode = clearButtonMode;
}
-(void)setText:(NSString *)text {
_textField.text = text;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
[self addSubview:self.textField];
}
*/
- (void)viewDidLoad {
[self addSubview:_textField];
}
- (void)viewWillAppear {
[self addSubview:_textField];
}
- (BOOL)textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string
{
if ([_delegate respondsToSelector:#selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
return [_delegate textField:textField shouldChangeCharactersInRange:range
replacementString:string];
}
return YES;
}
- (BOOL)textFieldShouldClear:(UITextField *)textField {
if ([_delegate respondsToSelector:#selector(textFieldShouldClear:)]) {
return [_delegate textFieldShouldClear:textField];
}
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
if ([_delegate respondsToSelector:#selector(textFieldDidBeginEditing:)]) {
[_delegate textFieldDidBeginEditing:textField];
}
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
if ([_delegate respondsToSelector:#selector(textFieldDidEndEditing:)]) {
[_delegate textFieldDidEndEditing:textField];
}
}
#end
And here is the code to add my custom wrapper to the table view:
} else if (indexPath.row == 1) {
cell.textLabel.text = #"Tax Rate";
if (!_textField) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(220.0, 8.0, 60.0, 26.0)];
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.adjustsFontSizeToFitWidth = YES;
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.keyboardType = UIKeyboardTypeDecimalPad;
textField.placeholder = kTaxRateDefault;
_textField = [[TUTextField alloc] initWithTextField:textField];
_textField.delegate = self;
// retrieve saved settings
_taxRate = [[SettingsSingleton sharedManager] taxRate];
if (![_taxRate isEqualToString:#""])
_textField.text = _taxRate;
}
UILabel *percentSign = [[UILabel alloc] initWithFrame:CGRectMake(285.0, 6.0, 20.0, 26.0)];
percentSign.text = #"%";
percentSign.backgroundColor = [UIColor clearColor];
[cell addSubview:_textField];
[cell addSubview:percentSign];
}
}
Any help appreciated!
I don't think this is the best way to extend a UITextField.
Instead of making an NSObject with a UITextField under it you should be saying something like:
Interface:
#interface UITextField (extendedUITextField) {
// Variables
}
//Methods
#end
Implementation:
#implementation UITextField (extendedUITextField)
// Method implement
#end
Hope this helps.

tableView doesn't show anything

I'm sure my code is withour mistake, because I have two same tableViews and both with same code, same content and same design. But I don't understand why one of my tableViews is shown, and the other one isn't. I'm using Dynamic Prototype Content, Grouped Style and both tableViews are in container view in other ViewController. Here is code:
table.h
#import <UIKit/UIKit.h>
#interface table : UIViewController <UITableViewDataSource, UITableViewDelegate>
{
NSArray *tabledata;
NSIndexPath* checkedIndexPath;
}
#property (nonatomic, retain) NSArray *tabledata;
#property (nonatomic, assign) int number;
#property (nonatomic, retain) NSIndexPath* checkedIndexPath;
#property (strong, nonatomic) IBOutlet UITableView *tableView;
+(table*)instance;
#property (nonatomic) NSInteger selectedRow;
#end
table.m
#import "table.h"
#interface table ()
#end
#implementation table
#synthesize tabledata;
#synthesize tableView;
#synthesize checkedIndexPath;
#synthesize number;
+(InstrumentsI*)instance {
static table *statInst;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
statInst = [[table alloc] init];
});
return statInst;
}
#synthesize selectedRow;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
tabledata = [[NSArray alloc] initWithObjects:#"row1", #"row2", #"row3", nil];
self.selectedRow = 0;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - TableView Data Source methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tabledata count];
}
- (UITableViewCell *)tableView:(UITableView *)tableview cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
cell = [tableview dequeueReusableCellWithIdentifier:#"identifer"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"identifer"];
}
cell.textLabel.text = [tabledata objectAtIndex:indexPath.row];
if (indexPath.row == self.selectedRow)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
#pragma mark TableView Delegate methods
- (void)tableView:(UITableView *)tableview didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[table instance].selectedRow = indexPath.row;
if (indexPath.row != self.selectedRow) {
self.selectedRow = indexPath.row;
}
[tableView reloadData];
}
- (void)viewDidUnload {
[self setTableView:nil];
[super viewDidUnload];
}
#end
Check if you have implemented all the delegates and datasource methods.
Also confirm that you have set your file's owner or controller as delegates and datasource.
Try to reload the tableview after loading the data, like:
- (void)viewDidLoad
{
[super viewDidLoad];
tabledata = [[NSArray alloc] initWithObjects:#"row1", #"row2", #"row3", nil];
self.selectedRow = 0;
[self.tableView reloadData];
}