Popover UITableViewController trigger action on mainView - iphone

I have an app that gives you a popOver Tableview controller. This popOver has n number of cells. I need to be able to call a function on the main view whenever one of the table cells in the popover is touched. How would I go about doing that?
It would be nice to able to dismiss the popover too once a cell is touched....
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Cell check %#", [totalArray objectAtIndex:indexPath.row]);
[self dismissPopoverAnimated:YES];
}
Here it will print the console the text in the cell, but I need to be able to pass that cell text back to the mainview... oh yeah, and the [self dismisspopoveranimated: yes] doesn't work...

The traditional way to address this is to make your "main" view controller a delegate of the class with the table view:
Define an application-specific delegate protocol, add a delegate method specific to your use case, and change your "main" view controller to conform to it. The delegate method should take a parameter whose type is the data you want to pass to the "main" view controller (in your case, either a UITableViewCell or the NSString containing its text).
Create a property on the class with the table view whose type is the new delegate protocol.
Pass your "main" view controller into the class with the table view by setting it as the value of the new property.
When the tableView:didSelectRowAtIndexPath: method is called, invoke the delegate method on the delegate you have created, passing in the data you want to give to the "main" view controller. This gives your "main" view controller an opportunity to respond to the fact that the table cell was selected in the popover, and it can call whatever function you need it to.
You can actually do the same thing in less code with blocks, but it's a bit more advanced. I won't get into that here.
You could also just use NSNotificationCenter, but personally I try to avoid using that unless absolutely necessary.

Related

How to switch view controller under this circumstance

I have a view controller that I need to refresh it self so, I basically reload it with the following code.
-(void)check{
GameController*myNewVC = [[GameController alloc] init];
[self presentModalViewController:myNewVC animated:NO];
}
I can call the method above in gamecontroller and it works fine, but in a button sub class I use the method below and it doesn't work because nothing happens.
.h
#interface CellButton : UIButton {
}
.m
GameController*myNewVC = [[GameController alloc] init];
[myNewVC check];
What can I do to get this working?
I have a view controller that I need to refresh it self so, I basically reload it
Don't do that. Your view controller isn't refreshing itself, it's replacing itself, and it's hard to think of a reason that it should need to do that.
Put the code the loads the data in a separate method, and call that method on the existing view controller instead of creating a whole new view controller. For example, many view controllers that manage a UITableView will call the table's -reloadData method to tell the table to discard any cells that are currently visible and request new ones. No matter what kind of view(s) your view controller manages, you can do something similar.
I can call the method above in gamecontroller and it works fine, but
in a button sub class I use the method below and it doesn't work
because nothing happens.
That's most likely because you say you're using the code in a UIButton subclass, and the code says:
[self presentModalViewController:myNewVC animated:NO];
So, the button is telling itself to present the view controller. However, UIButton doesn't have a presentModalViewController:animated: method. I'm surprised that "nothing happens" -- I'd expect an exception due to the unimplemented method. It should work fine if you replace self above with a pointer to your view controller. Or, much better, put the code in an IBAction method in the view controller, set the buttons action to that method, and its target to the view controller.
(from your comment...)
There is a function in the button class that will dictate weather or
not the view controller will refresh it self.
That sounds like a poor plan -- in a well designed MVC application, logic that controls whether the view controller will refresh belongs in the view controller. Have the view controller enable/disable or show/hide the button based on whatever conditions control the refreshing behavior.

Xcode error on superview of custom object

I have a custom table view controller called pfTableViewController and a custom cell called customTableViewCell.
From inside my customTableViewCell I try to access an NSMutableArray of the pfTableViewController:
- (IBAction)changeEditing:(UITextField *)sender {
pfTableViewController *pfWin = (pfTableViewController *) self.superview.superview;
[pfWin.pfFields replaceObjectAtIndex: myId withObject: #"some text"];
}
I used superview twice because the first one calls the UITableView and the second is supposed to call the pfTableViewController but it doesn't happen, I get this error:
2013-04-17 09:48:38.017 webgopher[21757:907]
-[UIViewControllerWrapperView pfFields]: unrecognized selector sent to instance 0x1d590d90
Any idea what's happening here?
If I use one more superview, it accesses the UINavigationTransitionView, that's too far I think!
Using something like superview.superview on apple implemented views like UITableViewCell is a very bad idea. You are relying on the view hierarchy not changing. This kind of thing can break very easily between versions of iOS.
You are also assuming the table view's super view is an instance of your view controller. But the view controller instance is not a view and not part of the view hierarchy. Instead you are getting a private apple view which wraps the view controller's view.
You should implement some kind of delegate method on your cell which is implemented by the view controller. This way the view controller can be directly notified of your "changeEditing" event without you having to crawl up private view hierarchies.
You can't access to a controller directly from its view. You need to look for the first controller through the responder chain. This post may be useful.-
How to get UIViewController of a UIView's superView in iPhone SDK?

Best approach to add Static-TableView-Cells to a UIViewcontroller?

I want to add a tableview-look-a-like-login to my app, but it seems to be not that easy to implement. I tried to accomplish my goal using more then one approach, but i am not sure about which solution is the best.
For example, Dropbox and Facebook have a login page like this.
Here are my 3 approaches :
I added 2 UITextfields to my View (no border) and placed a . png behind, which looks like a tableviewcell. ( Not the best approach cause i want to use real tableviews )
I added a Container View to my ViewController placed a tableview with static Table Views inside. The Problem here is, that i dont know how to access the information inside my viewcontroller?
I added a tableview to my ViewController and used dynamic cells with it. Connected the outlets for delegate and datasource to my viewcontroller and initialized them with the delegate and datasource methods. The Problem here is, that i can not use static table views inside a uiviewcontroller.
Is there any better way of solving this problem ?
I would really like to know how to do this in a more elegant way.
EDIT:
A ContainerViewController basically solved this issue for me some month ago.
After embedding one into the main controller you can access it through the prepareForSegue function and define a protocol-based interface for that specific controller to interact with the embedded controller.
If you want to use static cells inside a regular UIViewController, just add the static cells and design them the way you like in interface builder, then connect the table cells as strong IB outlets (weak won't work, make sure they are strongly referenced). This will work flawlessly if you have a few table cells. Then set the view controller as the data source of the tablet view, implement -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section to return the number of cells and implement -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath to return your strongly referenced cell instance for the specified index path. I've used this method for a simple table view in my view controller that had four cells and it is working perfectly. For a large-dynamic data set, I definitely do not recommend this approach but for small, static tables, this does the job right.
I have an idea how to solve this. I think it's a clean way to do so. You do not need storyboard for this controller.
Make your controller subclass UITableViewController like so:
#interface YourViewController : UITableViewController
Then in your viewDidLoad you create the instances of the cells:
- (void) viewDidLoad {
usernameCell = [YourTextFieldCell new];
passwordCell = [YourTextFieldCell new];
}
The YourTextFieldCell is of course your own subclass of a UITableViewCell, which could be something like this:
#implementation YourTextFieldCell {
UITextField textField;
}
- (id) init {
self = [super init];
if (self) {
// Adjust the text's frame field to your liking
textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 200, 20)];
[self addSubview:textField];
}
}
// A getter method to access the textfield from the outside
- (UITextField *) textField {
return textField;
}
#end
Back in YourViewController:
- (NSInteger) tableView:(UITableView *) tv numberOfRowsInSection:(NSInteger) section {
return 2;
}
- (UITableViewCell *) tableView:(UITableView *) tv cellForRowAtIndexPath:(NSIndexPath *) indexPath {
if (indexPath.row == 0) {
return usernameCell;
} else if (indexPath.row == 1) {
return passwordCell;
}
return nil;
}
Do you get where I am going with this? This is how I think you should do it! Good luck!
I think your approach 2 is the best. If you need to access information in the table view controller, from your UIViewController (which will be the parent view controller), you can get a reference to that table view controller with self.childViewControllers.lastObject. In the viewDidLoad method of the UIViewController subclass, you could set yourself as the delegate of the table view with this line if you want:
[[(UITableViewController *)self.childViewControllers.lastObject tableView] setDelegate:self];
That way, you could implement the tableView:didSelectRowAtIndexPath: method in the view controller, which will get the information I'm guessing you need.
If you go with your option 2) using a storyboard and have a ContainerView containing your own subclass of UITableViewController with static cells then you can implement the prepareForSegue: method in your parent ViewController to take a reference to the UITableViewController (it'll be the destinationController of the segue) and also to pass itself down to the UITableViewController subclass if necessary (which should hold onto it with a weak reference).
Disclaimer - This answer will work for any size of UITableView, but if you're just making a login view, Tom's answer will work quite well.
I'm not sure if this will help, but what I did for this was create my own UITableView-esque subclass with a UITableViewCell-esque subclass as well.
This may not be what you want to hear, but I find what I made to be really helpful, since I've used it a number of times now. Basically, you have a UIView with the stylistic approach for the different types (10.0f - 20.0f cornerRadius and a 1px border (divide by UIScreen's scale property for retina). As for the cell, you'll want to have a full sized UIButton on it that responds to your table view for the touch events either with a delegate or by setting the target and tag inside your table view's class.
Last, you'll have a delegate system just like the UITableView for your information for building the specific tables.
In short, you'll need:
2 UIView subclasses (TableView and TableViewCell)
2 Delegates/Protocols (TableViewDataSource and TableViewDelegate)
Optionally
1 Delegate (TableViewCellResponseDelegate)
1 NSObject Subclass (Contains all of the information needed in each cell - Ease of use)
I found Can's solution to be the best / easiest, but unfortunately it breaks in XCode 5.1 --
I found a workaround which builds off the same basic idea, but unfortunately requires a little more involvement: http://www.codebestowed.com/ios-static-tableview-in-uiviewcontroller/
To summarize, you can add TableViewCells directly to views (and create IBOutlets from them, etc), but in order for them to get "moved" to the TableView properly, you need to remove them from the view in code, and you also need to set Auto-Layout constraints in IB.

how to pick value from a uitableview and show it on previous page on a button

i want to use uitableview just like a uipickerview. on click a button the uitableview comes.and on clicking any cell the selected value will be shown on the button on previous page
The normal way to pass data back to another controller is to use a delegate protocol. The controller with the button would implement the protocol method(s) declared in an #protocol declaration put in the .h file of the table view controller. In the tableView:didSelectRowAtIndexPath: method, you would call the delegate method, passing the value of the clicked on cell.
rdelmar is correct, the simplest way to do this would probably be to use a delegate protocol and pass the selected value back to the previous view.
--
However, supposing you wanted to store this value outside of the table view and the picker, you could create a singleton or use NSUserDefaults to avoid having to pass the value around and potentially losing something. If this tableview/picker was in a settings menu or the like, that's what I would do.
See this for basics:
http://mobile.tutsplus.com/tutorials/iphone/nsuserdefaults_iphone-sdk/
Some code for delegation; A protocol in your tableview class:#protocol SelectionDelegate <NSObject>
-(void)setSelectedTableCellValue:(NSString*)value;#end Have your previous view confirm to and be the delegate for the tableview that you wish to display and also implement the protocol method. Now on cell selection, just retrieve the value for the cell and pass it over to your delegate via [delegate setSelectedTableCellValue:<some cell value>]; HTH.
You may want to take a look into core data, you will be able to save the data and re-access the data/value and reload in into any view controller you like. It is a very versatile tool, and once you learn it, you will be able to do so many things a lot easier. Take a look at this Tutorial
Just use this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UITableViewCell *cell=[self.m_TableView cellForRowAtIndexPath:indexPath];
AppDelegate* appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.m_SavedDictionary setObject:cell.textLabel.text forKey:#"driver"];
[self.navigationController popViewControllerAnimated:YES];
}
and on ViewwillAppear method of previous view use;
if([[appDelegate.m_SavedDictionary objectForKey:#"driver"]length]>=1)
{
[m_driverButton setTitle:[appDelegate.m_SavedDictionary objectForKey:#"driver"] forState:UIControlStateNormal];
}
Thats it.

Sharing data between iPhone tableviews?

I want to be able to share data between table views for an app that I'm making. The reason for this is that I want to be able to tell a subview which table row was selected so that I don't have to make a bunch of views and I can just test to see what the integer variable was. I watched a video tutorial on how to do this but they did not use tableviews. So when I tried this it did not seem to work. I used the app delegate as a "data center" that held that variables and then I tried to assign values to the variables in didSelectRowAtIndexPath method. (Pushing the new view works fine by the way it's just the shared application)
Here's the code for the first tableview where I assign the variable to a number.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger row = [indexPath row];
ApplicationAppDelegate *appDelegate = (ApplicationAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.rowPicked = row;
SecondLevelViewController *nextController = [self.controllers objectAtIndex:row];
[self.navigationController pushViewController:nextController animated:YES];
}
In the app delegate I did this and I synthesized it in the .m file:
#property (nonatomic) NSInteger rowPicked;
As well as other NSIntegers that I needed.
Any suggestions? If you think I'm doing this totally wrong could you please enlighten me with specific instructions or a link to a website or video tutorial?
Thank you all!
Here's how I usually accomplish this:
I don't use the AppDelegate for this. The logic and model data for both list and detail should reside in classes that make sense. In this case, we'll use the list and detail view controller classes themselves.
I'll begin by creating a UITableViewCell sublcass for the list view's row. In that sublcass, I'll create an ivar that houses the "entity" or whatever data the cell will need to display it's information. This can be an NSManagedObject or even an NSDictionary.
I'll override the setter of that ivar so that when data is set on the UITableViewCell, it updates the cell outlets to display it correctly. Notice how I keep the logic of how the cell is displayed contained completely within the subclass. It's important that you do things like this throughout your application to promote code cleanliness and organization.
In your tableView:didSelectRowAtIndexPath method, you'd then call the UITableView class' cellForRowAtIndexPath: method to return the cell that was selected. You can then cast it to your UITableViewCell subclass and get the entity information you set earlier.
Next, you'll need to create an ivar in your detail view controller. You'll want to set this variable from the tableView:didSelectRowAtIndexPath: method---right before you push the detail view onto the stack.
You should now have the necessary data in your detail view controller sublcass for processing, querying, or whatever.
Hope this helped!
It's really looks bad. Much better add id<$YOUR_PROTOCOL> delegate to SecondLevelViewcontroller and set nextController.delegate = self.
Protocol can looks like
#protocol RowAccessProtocol
#optional
-(NSUInteger)selectedRow;
#end
Your current tableViewController must be created:
#protocol RowAccessProtocol;
#class FirstLevelTableViewController:UITableViewController<RowAccessProtocol>
…
#end
And implementation:
…
-(NSUInteger)selectedRow{
return [self.tableView indexPathForSelectedRow].row;
}
In SecondLevelViewController you can call [self.delegate selectedRow] to get selected row.