Search Template tvOS - objective-c

Anybody know how to implement search template like in Apple tvOS Human Interface Guidelines, using native development in Objective-C or Swift, without TVML ?

So, after research I was able to find a solution:
Objective - C
If in application is tabBar, i created a subclass from UITabBarController e.g. APTabBarController. In APTabBarController, in method
- (void)viewDidLoad
I do next:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
SearchResultsViewController *myViewController = [storyboard instantiateViewControllerWithIdentifier:#"SearchResultsViewController"];
UISearchController *searchController = [[UISearchController alloc] initWithViewController:myViewController];
UISearchContainerViewController *containerVC = [[UISearchContainerViewController alloc] initWithSearchController: searchController];
containerVC.title = #"Search";
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController: containerVC];
NSMutableArray *newTab = [self.viewControllers mutableCopy];
[newTab addObject: navigationController];
[self setViewControllers: newTab];
Where:
storyboard - is my storyboard
SearchResultsViewController - is my controller from storyboard that contains collectionView
UISearchController - is controller that allow to find what do you need
UISearchContainerViewController - and these one is like a view controller from tabBarController
In "newTab" - I add fresh created viewController that i need
But, problem that I found is that i can't catch searched text. For that, create a subclass from UISearchController, and implement custom
initWithViewController
In my case it looks like these:
In .h
#import <UIKit/UIKit.h>
#interface SearchExercisesViewController : UISearchController
- (id) initWithViewController:(UIViewController *) viewController;
#end
In .m
#import "SearchExercisesViewController.h"
#interface SearchExercisesViewController () <UISearchBarDelegate>
#property (nonatomic, strong) UIViewController *viewController;
#end
#implementation SearchExercisesViewController
- (id) initWithViewController:(UIViewController *) viewController {
self = [super initWithSearchResultsController:viewController];
if (self) {
self.viewController = viewController;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.searchBar.delegate = self;
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSLog(#"%#",searchText);
}
#end
Profit, and now, replace
UISearchController *searchController = [[UISearchController alloc] initWithViewController:myViewController];
with
SearchExercisesViewController *searchController = [[SearchExercisesViewController alloc] initWithViewController:myViewController];
All done. Now only that remain is to sent data to viewController that contains collection view, and implement logic for search. For sent data you can you Delegate pattern or NSNotification. You can find how to implement that in that post:
it possible to Pass Data with popViewControllerAnimated?
Swift
In swift is the same, how to do that, you can find on Apple example from these link:
https://github.com/brunogb/TVExamples/tree/master/UIKitCatalogtvOSCreatingandCustomizingUIKitControls

Sounds like you want to look at UISearchController.

Related

Objective-C: Tabbaritem tapped->Method Called-> But WebView not refreshed

Trying to achieve
When I tap on the tabbaritem say #2, it will called the method and reload the web view.
Issue
When I tap on the tabbaritem, the method is called but web view did not reload.
Did not load the web view
Question
If I called the method on the VC itself. I can manage to reload the web view. Only if I called it when the tabbaritem is tapped, it doesn't reload the web view.
Code
MyTabBarController.m
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
NSLog(#"controller class: %#", NSStringFromClass([viewController class]));
NSLog(#"controller title: %#", viewController.title);
if (viewController == [tabBarController.viewControllers objectAtIndex:2])
{
[(UINavigationController *)viewController popToRootViewControllerAnimated:YES];
tabBarController.delegate = self;
[[[Classes alloc] init] LoadClasses];
}else if (viewController == [tabBarController.viewControllers objectAtIndex:3]){
[(UINavigationController *)viewController popToRootViewControllerAnimated:YES];
tabBarController.moreNavigationController.delegate = self;
[[[Gym alloc] init] handleRefreshGym:nil];
}else{
[(UINavigationController *)viewController popToRootViewControllerAnimated:NO];
}
}
Classes.m
- (void)LoadClasses {
sURL = #"www.share-fitness.com/apps/class.asp?memCode=SF100012&dtpClass=13/09/2018&lang=EN&lat=37.785835&long=-122.406418&ver=1&plat=IOS"
NSLog(#"The URL To be loaded %#", sURL);
NSURL *url = [NSURL URLWithString:sURL];
sRefresh = sURL;
[[NSURLCache sharedURLCache] removeAllCachedResponses];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[webView loadRequest:urlRequest];
[webView setDelegate:(id<UIWebViewDelegate>)self];
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[webView.scrollView addSubview:refreshControl];
}
As I mentioned in my other reply Objective-C: How to properly set didSelectViewController method for TabBarController, so I can refresh the VC everytime it is tapped, I don't think it's good User Experience to be refreshing the view from the server every time the tab bar is selected (this will get very annoying for users to wait every time for the server to refresh the data)
That being said, the issue with the code you posted is that you're initializing a new instance of your classes in the TabBarControllerDelegate method so the method will be called on this new instance instead of on the one that's displaying/exists in your TabBarController's view controllers. Specifically these two lines are initializing the new instances:
[[[Classes alloc] init] LoadClasses];
[[[Gym alloc] init] handleRefreshGym:nil];
Instead you should be finding the instance that already exists, and calling the method on them.
I would recommend creating a ParentViewController with a public method along the lines of - (void)doStuffWhenTabBarControllerSelects; (just example naming to be clear what's it doing to you) then have each of the view controllers you'd like to have do something when they're selected be child classes of this parent (and have their own implementation of - (void)doStuffWhenTabBarControllerSelects;). This way in the TabBarController's delegate method, you can just find the appropriate instance of ParentViewController (associated with the view controller being selected) and call the - (void)doStuffWhenTabBarControllerSelects; method on it.
Here's an example of what I mean:
ParentViewController.h:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
#interface ParentViewController : UIViewController
- (void)doStuffWhenTabBarControllerSelects;
#end
NS_ASSUME_NONNULL_END
ParentViewController.m:
#import "ParentViewController.h"
#interface ParentViewController ()
#end
#implementation ParentViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)doStuffWhenTabBarControllerSelects {
NSLog(#"Fallback implementation if this method isn't implemented by the child class");
}
#end
FirstViewController.h:
#import <UIKit/UIKit.h>
#import "ParentViewController.h"
#interface FirstViewController : ParentViewController
#end
FirstViewController.m:
#import "FirstViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)doStuffWhenTabBarControllerSelects {
NSLog(#"I'm doing stuff on the %# when the tab bar controller delegate calls back to selection", NSStringFromClass([self class]));
}
#end
SecondViewController.h:
#import <UIKit/UIKit.h>
#import "ParentViewController.h"
#interface SecondViewController : ParentViewController
#end
SecondViewController.m:
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)doStuffWhenTabBarControllerSelects {
NSLog(#"I'm doing stuff on the %# when the tab bar controller delegate calls back to selection", NSStringFromClass([self class]));
}
#end
MyTabBarController.h:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
#interface MyTabBarController : UITabBarController <UITabBarControllerDelegate>
#end
NS_ASSUME_NONNULL_END
MyTabBarController.m:
#import "MyTabBarController.h"
#import "ParentViewController.h"
#implementation MyTabBarController
- (void)viewDidLoad {
[super viewDidLoad];
self.delegate = self;
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
// since your view controllers are embedded in nav controllers, let's make sure we're getting a nav controller
if ([viewController isKindOfClass:[UINavigationController class]]) {
// we're expecting a nav controller so cast it to a nav here
UINavigationController *navController = (UINavigationController *)viewController;
// now grab the first view controller from that nav controller
UIViewController *firstViewControllerInNav = navController.viewControllers.firstObject;
// check to make sure it's what we're expecting (ParentViewController)
if ([firstViewControllerInNav isKindOfClass:[ParentViewController class]]) {
// cast it to our parent view controller class
ParentViewController *viewControllerToCallMethodOnAfterSelection = (ParentViewController *)firstViewControllerInNav;
[viewControllerToCallMethodOnAfterSelection doStuffWhenTabBarControllerSelects];
}
}
}
#end
Then when you select between the two tabs you'll this is the output:
I'm doing stuff on the FirstViewController when the tab bar controller delegate calls back to selection
I'm doing stuff on the SecondViewController when the tab bar controller delegate calls back to selection
I'd recommend doing some additional research/reading of the documentation:
There's a good amount of beginner information here: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/DefiningClasses/DefiningClasses.html#//apple_ref/doc/uid/TP40011210-CH3-SW1
UITabBarController: https://developer.apple.com/documentation/uikit/uitabbarcontroller?language=objc
UITabBarControllerDelegate:
https://developer.apple.com/documentation/uikit/uitabbarcontrollerdelegate?language=objc
One other helpful hint is that within Xcode you can hold down on the option key and click on something to show a quicklook into the explanation/documentation
You can also right click on something and "Jump To Definition". The majority of Apple's implementations will will have additional information in the header.
Here's the example of what's in the header of UITabBarController:
/*!
UITabBarController manages a button bar and transition view, for an application with multiple top-level modes.
To use in your application, add its view to the view hierarchy, then add top-level view controllers in order.
Most clients will not need to subclass UITabBarController.
If more than five view controllers are added to a tab bar controller, only the first four will display.
The rest will be accessible under an automatically generated More item.
UITabBarController is rotatable if all of its view controllers are rotatable.
*/
NS_CLASS_AVAILABLE_IOS(2_0) #interface UITabBarController : UIViewController <UITabBarDelegate, NSCoding>
As well as under the Help Menu there's "Developer Documentation" (CMD + SHIFT + 0) which has a multitude of useful information.

How to continouse pass value from one ViewController to second Viewcontroller and automatic close, dismiss 2nd ViewController

I try to pass data from one ViewController to secondControler however seem it not work. I use NSNotification.
- 2 Controller have same class "ViewController"
In viewcontroller.m
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(ProcessBarLoading) name:#"buttonPressed" object:nil];
}
-(void)ProcessBarLoading{
_labelTest.stringValue = #"TESTING";
}
- (IBAction)test:(id)sender {
[[NSNotificationCenter defaultCenter] postNotificationName:#"buttonPressed" object:self];
NSStoryboard *storyboard = [NSStoryboard storyboardWithName:#"Main" bundle: nil];
NSViewController * vc = [storyboard instantiateControllerWithIdentifier:#"SheetViewController"];
[self presentViewControllerAsSheet:vc];
}
When run program and press button, there're no update Label Text at all. Do you know why and how I can fix.
New Code:
In SecondViewController.m
#interface SencondViewController ()
#end
#implementation SencondViewController
#synthesize progressValue;
#synthesize labelView;
- (void)viewDidLoad {
[super viewDidLoad];
// Do view setup here.
labelView.stringValue =progressValue;
}
In FirstViewCOntroller:
- (IBAction)test:(id)sender {
self->uide = #"0";
[self performSegueWithIdentifier:#"showRecipeDetail" sender:self->uide];
NSStoryboard *storyboard = [NSStoryboard storyboardWithName:#"Main" bundle: nil];
NSViewController * vc = [storyboard instantiateControllerWithIdentifier:#"SheetViewController"];
[self presentViewControllerAsSheet:vc];
- (void)prepareForSegue:(NSStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showRecipeDetail"]) {
SencondViewController * secondVC = segue.destinationController;
secondVC.progressValue = uide;
}
}
- (IBAction)test2:(id)sender {
uide = #"80";
[self performSegueWithIdentifier:#"showRecipeDetail" sender:uide];
[self.view displayIfNeeded];
}
So whether I press Button 1(test) other Button2 (test2) alway show new view with update value. What I need is only show 1 view.
Why do you need use a nsnotification the easy way is use a prepareForSegue or Delegation
This is an examample
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if ([segue.identifier isEqualToString:#"myId"]) {
SecondViewController *vc = segue.destinationViewController;
vc.myDataToPass = self.myValueInMyFirstViewController;
}
}
Notification pattern is not recommended for doing this. Use notification
when you want to pass some data to multiple objects on some event.
To solve this problem:
Step 1:
You should change your View Controller names to FirstViewController and SecondViewController, and have a property declared in your SecondViewController whose value you want to set from the FirstViewController.
Step 2:
Finally, in the prepare for Segue method of the FirstViewController, set the data.
In Objective-C, you can try this code:
#import "FirstViewController.h"
#import "SecondViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
//This will trigger the prepareForSegue method
-(IBAction) someButtonClick {
[self performSegueWithIdentifier:#"YourSequeId" sender:nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
SecondViewController * secondVC = segue.destinationViewController;
secondVC.someValue = #"PassYourValueHere";
}
#end
and in the header file of the SecondViewController, declare the property:
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
#property (nonatomic,strong) NSString *someValue;
#end
In the implementation file of the SecondViewController, write:
#import "SecondViewController.h"
#interface SecondViewController ()
#property (nonatomic,weak) IBOutlet UITextField *yourTextField;
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.yourTextField.text = self.someValue
// Do any additional setup after loading the view.
}
#end

Mac OSX Storyboard : communicate between NSViewController

I use storyboard in a OS X cocoa application project with a SplitView controller and 2 others view controller LeftViewController and RightViewController.
In the LeftViewController i have a tableView that display an array of name. The datasource and delegate of the tableview is the LeftViewController.
In the RightViewController i just have a centered label that display the select name. I want to display in the right view the name selected in the left view.
To configure the communication between the 2 views controllers i use the AppDelegate and i define 2 property for each controller in AppDelegate.h
The 2 property are initialized in the viewDidLoad of view controller using the NSInvocation bellow :
#implementation RightViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
id delg = [[NSApplication sharedApplication] delegate];
SEL sel1 = NSSelectorFromString(#"setRightViewController:");
NSMethodSignature * mySignature1 = [delg methodSignatureForSelector:sel1];
NSInvocation * myInvocation1 = [NSInvocation
invocationWithMethodSignature:mySignature1];
id me = self;
[myInvocation1 setTarget:delg];
[myInvocation1 setSelector:sel1];
[myInvocation1 setArgument:&me atIndex:2];
[myInvocation1 invoke];
}
I have the same in LeftViewController.
Then if i click on a name in the table view, i send a message to the delegate with the name in parameter and the delegate update the label of the RightViewController with the given name. It works fine but according to apple best practice it’s not good.
Is there another way to communicate between 2 view controller inside a storyboard ?
I've already read a lot of post but found nothing for OS X.
You can download the simple project here : http://we.tl/4rAl9HHIf1
This is more advanced topic of app architecture (how to pass data).
Dirty quick solution: post NSNotification together with forgotten representedObject:
All NSViewControllers have a nice property of type id called representedObject. This is one of the ways how to pass data onto NSViewController. Bind your label to this property. For this simple example we will set representedObject some NSString instance. You can use complex object structure as well. Someone can explain in comments why storyboards stopped to show representedObject (Type safety in swift?)
Next we add notification observer and set represented object in handler.
#implementation RightViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserverForName:#"SelectionDidChange" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
//[note object] contains our NSString instance
[self setRepresentedObject:[note object]];
}];
}
#end
Left view controller and its table:
Once selection changes we post a notification with our string.
#interface RightViewController () <NSTableViewDelegate, NSTableViewDataSource>
#end
#implementation RightViewController
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
return [[self names] count];
}
- (nullable id)tableView:(NSTableView *)tableView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
{
return [self names][row];
}
- (NSArray<NSString *>*)names
{
return #[#"Cony", #"Brown", #"James", #"Mark", #"Kris"];
}
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
NSTableView *tableView = [notification object];
NSInteger selectedRow = [tableView selectedRow];
if (selectedRow >= 0) {
NSString *name = [self names][selectedRow];
if (name) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"SelectionDidChange" object:name];
}
}
}
PS: don't forget to hook tableview datasource and delegate in storyboard
Why is this solution dirty? Because once your app grows you will end up in notification hell. Also view controller as data owner? I prefer window controller/appdelegate to be Model owner.
Result:
AppDelegate as Model owner.
Our left view controller will get it's data from AppDelegate. It is important that AppDelegate controls the data flow and sets the data (not the view controller asking AppDelegate it's table content cause you will end up in data synchronization mess). We can do this again using representedObject. Once it's set we reload our table (there are more advanced solutions like NSArrayController and bindings). Don't forget to hook tableView in storyboard. We also modify tableview's delegate methos the tableViewSelectionDidChange to modify our model object (AppDelegate.selectedName)
#import "LeftViewController.h"
#import "AppDelegate.h"
#interface LeftViewController () <NSTableViewDelegate, NSTableViewDataSource>
#property (weak) IBOutlet NSTableView *tableView;
#end
#implementation LeftViewController
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
return [[self representedObject] count];
}
- (nullable id)tableView:(NSTableView *)tableView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
{
return [self representedObject][row];
}
- (void)setRepresentedObject:(id)representedObject
{
[super setRepresentedObject:representedObject];
//we need to reload table contents once
[[self tableView] reloadData];
}
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
NSTableView *tableView = [notification object];
NSInteger selectedRow = [tableView selectedRow];
if (selectedRow >= 0) {
NSString *name = [self representedObject][selectedRow];
[(AppDelegate *)[NSApp delegate] setSelectedName:name];
} else {
[(AppDelegate *)[NSApp delegate] setSelectedName:nil];
}
}
In RightViewController we delete all code. Why? Cause we will use binding AppDelegate.selectedName <--> RightViewController.representedObject
#implementation RightViewController
#end
Finally AppDelegate. It needs to expose some properties. What is interesting is how do I get my hands on all my controllers? One way (best) is to instantiate our own window controller and remember it as property. The other way is to ask NSApp for it's windows (be careful here with multiwindow app). From there we just ask contentViewController and loop through childViewControllers. Once we have our controllers we just set/bind represented objects.
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (nonatomic) NSString *selectedName;
#property (nonatomic) NSMutableArray <NSString *>*names;
#end
#import "AppDelegate.h"
#import "RightViewController.h"
#import "LeftViewController.h"
#interface AppDelegate () {
}
#property (weak, nonatomic) RightViewController *rightSplitViewController;
#property (weak, nonatomic) LeftViewController *leftSplitViewController;
#property (strong, nonatomic) NSWindowController *windowController;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
_names = [#[#"Cony", #"Brown", #"James", #"Mark", #"Kris"] mutableCopy];
_selectedName = nil;
NSStoryboard *storyboard = [NSStoryboard storyboardWithName:#"Main"
bundle:[NSBundle mainBundle]];
NSWindowController *windowController = [storyboard instantiateControllerWithIdentifier:#"windowWC"];
[self setWindowController:windowController];
[[self windowController] showWindow:nil];
[[self leftSplitViewController] setRepresentedObject:[self names]];
[[self rightSplitViewController] bind:#"representedObject" toObject:self withKeyPath:#"selectedName" options:nil];
}
- (RightViewController *)rightSplitViewController
{
if (!_rightSplitViewController) {
NSArray<NSViewController *>*vcs = [[[self window] contentViewController] childViewControllers];
for (NSViewController *vc in vcs) {
if ([vc isKindOfClass:[RightViewController class]]) {
_rightSplitViewController = (RightViewController *)vc;
break;
}
}
}
return _rightSplitViewController;
}
- (LeftViewController *)leftSplitViewController
{
if (!_leftSplitViewController) {
NSArray<NSViewController *>*vcs = [[[self window] contentViewController] childViewControllers];
for (NSViewController *vc in vcs) {
if ([vc isKindOfClass:[LeftViewController class]]) {
_leftSplitViewController = (LeftViewController *)vc;
break;
}
}
}
return _leftSplitViewController;
}
- (NSWindow *)window
{
return [[self windowController] window];
}
//VALID SOLUTION IF YOU DON'T INSTANTIATE STORYBOARD
//- (NSWindow *)window
//{
// return [[NSApp windows] firstObject];
//}
#end
Result: works exactly the same
PS: If you instantiate own window Controller don't forget to delete initial controller from Storyboard
Why is this better? Cause all changes goes to model and models sends triggers to redraw views. Also you will end up in smaller view controllers.
What can be done more? NSObjectController is the best glue between your model objects and views. It also prevents retain cycle that sometimes can happen with bindings (more advanced topic). NSArrayController and so on...
Caveats: not a solution for XIBs
I managed to get what i want by adding the following code in AppDelegate.m :
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
//
NSStoryboard *storyboard = [NSStoryboard storyboardWithName:#"Main"
bundle:[NSBundle mainBundle]];
self.windowController = [storyboard instantiateControllerWithIdentifier:#"windowController"];
self.window = self.windowController.window;
self.splitViewController = (NSSplitViewController*)self.windowController.contentViewController;
NSSplitViewItem *item0 = [self.splitViewController.splitViewItems objectAtIndex:0];
NSSplitViewItem *item1 = [self.splitViewController.splitViewItems objectAtIndex:1];
self.leftViewController = (OMNLeftViewController*)item0.viewController;
self.rightViewController = (OMNRightViewController*)item1.viewController;
[self.window makeKeyAndOrderFront:self];
[self.windowController showWindow:nil];
}
We also need to edit the storyboard NSWindowController object as follow :
Uncheck the checkbox 'Is initial controller' because we add it programmatically in AppDelegate.m.
Now the left and right view can communicate. Just define a property named rightView in OMNLeftViewController.h :
self.leftViewController.rightView = self.rightViewController;

Button that takes me to a new UIViewController based on the content of a TextField not working

I'm trying to make a button take me to a new UIViewController based on the content of a textField, but when I run it and hit the button (with the right condition in the text field to take me to the new UIViewController), the screen blacks out. This is what I wrote in my .h and .m files. Can anyone help me (Im using storyboards)
#interface ViewController : UIViewController
- (IBAction)boton:(id)sender;
#property (strong, nonatomic) IBOutlet UITextField *texto;
#end
#import "ViewController.h"
#import "ViewController2.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize texto;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)boton:(id)sender {
if ([texto.text isEqualToString:#"1"]) {
ViewController2 *vc1=[[ViewController2 alloc]init];
[self presentViewController:vc1 animated:YES completion:nil];
}
}
#end
As you say the screen is blacking out, I expect your viewController is getting initialised without a view.
To initialise with a view hierarchy from a xib(nib) file:
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
where nibName can be nil if it shares it's name with the View Controller, and nibBundle can be nil it the nib is in the main bundle.
i.e....
ViewController2 *vc2;
vc2 = [[ViewController2 alloc] initWithNibName:nil
bundle:nil];
where the xib file is named ViewController2.xib
To initialise from a storyboard:
UIStoryboard *storyboard = self.storyboard;
vc2 = [storyboard instantiateViewControllerWithIdentifier:#"ViewController2"];
(you need to set up a viewController in storyboard and give it a matching identifier)
To initialise with neither storyboard or xib, you should override your view controller's - (void)loadView, create a view and assign it to self.view.
Update
In answer to your comment - the UIStoryboard... and ViewController2 *vc2= ... code would go into your button code (in your case it you would replace / adapt the line containing vc1=.... It would look like this:
- (IBAction)boton:(id)sender {
if ([texto.text isEqualToString:#"1"]) {
ViewController2 *vc2;
UIStoryboard *storyboard = self.storyboard;
vc2 = [storyboard instantiateViewControllerWithIdentifier:#"ViewController2"];
[self presentViewController:vc2 animated:YES completion:nil];
}
You will need to have created a storyboard scene in your storyboard with a viewController whose custom class is ViewController2 and identifier is "ViewController2". The identifier name is arbitrary, but must match the identifier string you use in your code.
As you are using storyboards, an alternative way to do this is to create a modal segue from the 'ViewController' scene to a 'ViewController2' scene, give it an identifier, and use performSegueWithIdentifier in your button method.

How to replace current viewController with a new viewController

I'm trying to replace my current viewController with a new one. I've been able to do this before but I'm having some issues with BAD_ACCESS.
This is the code that will run when I want to replace the current view with a new one.
(The function will be called using a local property "self.some_data" (nonatomic, retain))
-(void) labelSelected:(SomeDataObject*) some_data{
SomeViewController *viewController = (SomeViewController*)[[ClassManager sharedInstance] viewControllerForClassIdentifier:#"com.somename" fromPlistFileName:#"iPhoneScreenList"];
viewController.data = (NSObject*)some_data;
[some_data retain];
//[self.navigationController pushViewController:viewController animated:YES];
UINavigationController *tempNavigationController = self.navigationController;
[[self retain] autorelease];
[tempNavigationController popViewControllerAnimated:FALSE];
[tempNavigationController pushViewController:viewController animated:TRUE];
}
Here everything works fine. The issue is that if I release the new "viewController" it crashes. And if I choose:
[tempNavigationController popViewControllerAnimated:TRUE];
I get some really wierd behaviour where the controller never gets replace and I return to the rootController and the navigation bar has two layers of text on it.
And if I do this:
[tempNavigationController pushViewController:viewController animated:FALSE];
I get BAD_ACCESS and the application chrashes. It worked before but not anymore.
What am I doing wrong?
Thanks!
Use category for controller replace:
// UINavigationController+ReplaceStack.h
#interface UINavigationController (ReplaceStack)
- (void) replaceLastWith:(UIViewController *) controller;
#end
// UINavigationController+ReplaceStack.m
#import "UINavigationController+ReplaceStack.h"
#implementation UINavigationController (ReplaceStack)
- (void) replaceLastWith:(UIViewController *) controller {
NSMutableArray *stackViewControllers = [NSMutableArray arrayWithArray:self.viewControllers];
[stackViewControllers removeLastObject];
[stackViewControllers addObject:controller];
[self setViewControllers:stackViewControllers animated:YES];
}
#end