Forced Updated Display view controller from .xib - objective-c

I am attempting to display a view controller from .xib that indicates to a user that an update to the app is available. For some reason, the following code seems to do nothing:
if ([serverObject[#"newServerBuilt"] isEqualToString:#"YES"]) {
//we want to display the text from the server to user
NSString * displayText=serverObject[#"displayText"];
ForceUpdate * forceUpdateViewController = [[ForceUpdate alloc] initWithNibName:#"ForceUpdate" bundle:nil];
forceUpdateViewController.textToShow=displayText;
[self presentViewController:forceUpdateViewController animated:NO completion:nil];
}
Does anyone know why? As you can see, I'm allowing myself to display an update view controller based upon a customizable message on the server.
Also, when I click on a textlabel in the .xib, it says the textlabel connects to the "File's ownder" but should it connect to "Forced Update"?
and the forced update.h looks like so:
#import <UIKit/UIKit.h>
#interface ForceUpdate : UIView
#property (nonatomic, strong) NSString * textToShow;
#end

I guess you would be doing it in AppDelegate.m file. if YES then you need to presentViewController from [[[UIApplication sharedApplication] keyWindow] rootViewController] insetead self.
[[[[UIApplication sharedApplication] keyWindow] rootViewController] presentViewController:forceUpdateViewController animated:NO completion:nil];

Related

Setting a delegate property of a controller to self is causing a crash in my app

I have 3 controllers:
SearchViewController
CollectionViewController
MainViewController
In short
In CollectionViewController I can access SearchViewController by tapping the magnify glass in the nav bar. I can then search for a specific item. Then select a result from the rows returned. Once I tap a row the SearchViewController is dismissed and a query is performed on the CollectionViewController.
However on MainViewController things don't work the same. Because when the SearchViewController is accessed from the MainViewController and dismissed it's the MainViewController that appears because that is where the SearchViewController was initialized from so I have to do some extra work to get me to the CollectionViewController to perform the query. I performed in first paragraph.
There is a protocol/delegate method I set in the MainViewController that notifies the CollectionViewController when the SearchViewController is dismissed that is causing the app to crash. I can't figure out why. Please read on to for a better explanation of what is going on.
In long
Customer types what they want to search for in the search box of the SearchViewController and when they tap the row in the associated tableView of results the SearchViewController is dismissed and it's parent CollectionViewController is now on screen. When this controller is dismissed I use a delegate to notify CollectionViewController that the SearchViewController was dismissed.
Notify CollectionViewController about dismissal of SVC then perform a query:
- (void)searchViewControllerDismissed:(VAGSearchViewController*)searchViewController withTitleForObject:(NSString *)titleString
{
_searchTitleString = titleString;
[self setObjects:nil];
[self performQuery];
}
This all works fine. However I have another controller MainViewController. SearchViewController can be accessed from MainViewController but I can't dismiss and perform a query the way I did when I accessed SearchViewController from CollectionViewController because when the SearchViewController is dismissed MainViewController is present on screen because it was the controller I accessed the SearchViewController from.
What I decided to do was detect which controller initialised SearchViewController then use the same delegate method from above to notify that controller when the SearchViewController was dismissed.
Inside SearchViewController:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
// If count of child view controllers is greater than 1 then we are not on main table view controller
if ([[[self presentingViewController] childViewControllers] count] > 1) {
[self dismissViewControllerAnimated:NO completion:^{
[[self delegate] searchViewControllerDismissed:self withTitleForObject:[[cell textLabel] text]];
}];
} else {
[self dismissViewControllerAnimated:NO completion:^{
[[self delegate] searchViewControllerDismissed:self withTitleForObject:[[cell textLabel] text]];
}];
}
}
This works fine. So now I created a protocol inside MainViewController.
Inside MainViewController.h:
#class VAGMainTableViewViewController;
#protocol VAGMainTableViewControllerDisappearedDelegate <NSObject>
- (void)mainTableViewControllerDisappearedwithTitleForObject:(NSString *)titleString;
#end
#interface VAGMainTableViewController : UITableViewController
#property (nonatomic, weak) id<VAGMainTableViewControllerDisappearedDelegate> disappearDelegate;
What I wanted was this delegate method to then notify CollectionViewController that SearchViewController had been dismissed from MainViewController then perform a query.
Here is the code inside MainViewController.m:
- (void)searchViewControllerDismissed:(VAGSearchViewController *)searchViewController withTitleForObject:(NSString *)titleString
{
self.disappearDelegate = self;
[[self disappearDelegate] mainTableViewControllerDisappearedwithTitleForObject:titleString];
[self performSegueWithIdentifier:#"garmentsCollectionSegue" sender:nil];
}
This is crashing with:
[VAGMainTableViewController mainTableViewControllerDisappearedwithTitleForObject:]: unrecognized selector sent to instance 0xf0140f0
When I comment out the line where I set the disappearDelegate line the crash goes away and I am pushed to the CollectionViewController (garmentsCollectionSegue). But the data passed in the delegate method is received by CollectionViewController obviously because a delegate is set.
I've done enough messing around and I think the problem I'm having is caused by not properly setting a delegate or not setting it in the correct place.
Would appreciate some help.
Thanks for your time.
It seems that you are setting the MainViewController as delegate of itself. I don't think that is what you want.
You want to use that delegate protocol to inform the CollectionViewController of what happens in the MainViewController, right?
Then CollectionViewController should be the disappearDelegate.
So try instead:
CollectionViewController *collectionVC = //this depends on your app structure, get the controller
self.disappearDelegate = collectionVC;

UIPopovercontroller in UISplitViewController

My detailviewcontroller is called myDetailVC , with tableVC which is just a table on the side of myDetailVC.
in myDetailVC, I have a button that is supposed to show a popoverviewcontroller. However, it crashes when I press it.
in my .h file:
#property (strong, nonatomic) UIPopoverController *masterPopOverController;
and .m:
- (IBAction)goToPDF:(id)sender
{
viewPDFViewController *MPPWV =[[viewPDFViewController alloc] initWithNibName:nil bundle:nil];
self.masterPopOverController = [[UIPopoverController alloc] initWithContentViewController:MPPWV];
[self.masterPopOverController presentPopoverFromRect:[sender frame] inView:[sender superview] permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[self.masterPopOverController setPopoverContentSize:CGSizeMake(100, 100) animated:NO];
}
Everything is connected fine in my xib, since I tested it by making it push to a viewcontroller instead of a popover. Can someone help me with this?
First, it looks like you're loading it up with a view controller that doesn't have anything in it:
viewPDFViewController *MPPWV =[[viewPDFViewController alloc] initWithNibName:nil bundle:nil];
Try specifying a Nib name, if you have one. It's possible that you don't have a NIB for that view controller. If that's the case you probably have a designated initializer -init method that you should be calling on it. Do that instead of calling -initWithNibName:
Second, it doesn't look like you're retaining the view controller you're loading into the pop over. It's possible that they require strong references. Try retaining it via property (or an ivar):
#property (nonatomic, strong) viewPDFViewController * MMPPWV;
Then when you access it do so via self:
self.MPPWV = [[viewPDFViewController alloc] initWithNibName:nil bundle:nil];

iPhone back button refuses to work after selecting an image with the UIImageViewController? [duplicate]

This question already has answers here:
iPhone - UIImagePickerControllerDelegate inheritance
(2 answers)
Closed 9 years ago.
So I am writing this iPad app that starts on a main screen and then from there you can go to a settings page. In the settings page you have the ability to select a picture from the photo album using a UIImagePickerController in a popover view.
If I go to the settings page and then press the back button to return to the main page everything works as expected. But if I go to settings and pick an image the back button on the page will not let me go back to the main page.
The popover and UIImagePickerController seem to be working fine so I do not know what is causing this. Here is my code for the UIImagePickerController.
- (IBAction)imagePick1:(id)sender {
pickerController = [[UIImagePickerController alloc] init];
[pickerController setDelegate:self];
[pickerController setSourceType:UIImagePickerControllerSourceTypeSavedPhotosAlbum];
[pickerController setAllowsEditing:NO];
popoverController = [[UIPopoverController alloc] initWithContentViewController:pickerController];
[popoverController setDelegate:self];
[popoverController presentPopoverFromRect:[[self imageButton1] frame] inView:[self view] permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
...
- (void)imagePickerController:(UIImagePickerController *)pickerController1 didFinishPickingMediaWithInfo:(NSDictionary *)info
{
image1 = [info objectForKey:UIImagePickerControllerOriginalImage];
_image1.image = image1;
[popoverController dismissPopoverAnimated:YES];
}
When I try to press the back button the app freezes and it won't respond to any more commands. What am I doing wrong?
Edit: I ran it again and this is the error I got in the log when pressing the back button.
-[__NSCFType dismissPopoverAnimated:]: unrecognized selector sent to instance 0x7128cd0
Also here is the beginning of my header file.
#interface ViewController : UIViewController
<UIPickerViewDataSource, UIPickerViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIPopoverControllerDelegate>{
UIPopoverController *popoverController;
}
#property (nonatomic, retain) UIPopoverController *popoverController;
Possible duplicate. See here
Have you declared the delegate in the header file as well like below? Please also make sure your delegates conforms to the UINavigationControllerDelegate as well, as the UIImagePickerControllerDelegate directly inherits from UINavigationControllerDelegate, however all the UINavigationControllerDelegate methods are optional.
#interface MyViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
edit: Based on your edit, it appears that you need to also add the "UIPopoverControllerDelegate" to your header file. You also need to add [popoverController setDelegate:self] after your allocation.
edit 2: Ok now you need to declare this method as well in your implementation (.m) file.
and return yes.
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController {
return YES;
}
edit 3: Why are you are setting dismissPopoverAnimated to NO and releasing popoverController while it is still showing?
[popoverController dismissPopoverAnimated:NO];
[popoverController release];
try setting the dismissPopoverAnimated to YES and remove the release for now. By the way, is popoverController retained as a property in your header file? Are you using ARC? if you are using ARC you should not be calling release on the popoverController.
edit 4:
try modifying the header to this:
UIPopoverController *_popoverController;
#property (nonatomic, retain) UIPopoverController *popoverController
and add #synthesize popoverController = _popoverController; to your implementation file.
now start replacing all the instances of "popoverController" with "_popoverController" in your implementation file.
Also replace [popoverController dismissPopoverAnimated:YES]; with
if(_popoverController != nil)
[_popoverController dismissPopoverAnimated:YES];
let me know the results below.

View properties resetting after view change

I've been trying to make this work for a while now with no chance, every time I change from view to view, the view's variables and content are reset to 'default' e.g if in a view I changed a label's text field from the default 'Label' to 'Hello, and then change views, once I come back to the same view, the text will be 'Label' again.
The only way I've gotten around this so far is to set a static string and then change Label.text to string in viewDidLoad. I just KNOW that this isn't the way to do it. I have a hunch that it's to do with how I transition from view to view, (allocating and initiating etc.)
Current way I transition:
FirstView.h:
#interface FirstView : Engine
#property(nonatomic, readwrite) MainGameDisplay *secondView;
FirstView.m:
#implementation FirstView
- (IBAction)StartGame:(id)sender
{
if (! self.secondView)
self.secondView = [[MainGameDisplay alloc] initWithNibName:nil bundle:nil];
[self presentViewController: self.secondView animated:YES completion:NULL];
}
And MainGameDisplay:
MainGameDisplay.h:
#class ViewController;
#interface MainGameDisplay : Engine
#property (strong) ViewController *firstPage;
MainGameDisplay.m:
#implementation MainGameDisplay
- (IBAction)returnToHome:(id)sender {
if (!self.firstPage)
self.firstPage = [[ViewController alloc] initWithNibName:nil bundle:nil];
[self presentViewController: self.firstPage animated:YES completion:NULL];
}
What I would like is to not have to set all of the values again through viewDidLoad, I just cant see it as being a good programming style.
You're right in your suspicions about what's gone wrong. Although you call your method returnToHome: you aren't really returning anywhere but rather stacking a new copy of ViewController on top of whatever you already have.
To actually go back, the opposite of presentViewController: is dismissViewControllerAnimated:. Try using that inside your MainGameDisplay class when the button is pressed to go back.

Jump between different viewControllers using UIButton?

I have a button that open another viewController(familyView) when clicked.
In familyView there is another button which suppose to bring me back to the mainViewController(ViewController.xib) but I don't know how to call the main viewController.
My method to call familyView
UIViewController* familyView = [[UIViewController alloc] initWithNibName:#"familyView" bundle:[NSBundle mainBundle]];
[self.view addSubview:familyView.view];
I hope you could help on how to call the main ViewController ? do I have to use the same method to call it? like this I mean:
UIViewController* mainView = [[UIViewController alloc] initWithNibName:#"viewController" bundle:[NSBundle mainBundle]];
[self.view addSubview:mainView.view];
If yes, is there a better way to implement this? in my demo project, I'm trying to make 7 views full with data and a button to go back and forth.
EDIT:
If I use UIView would that be best for me instead of using different viewControllers with their implementations and interfaces files?
My project will have views, and each view has data on it parsed from a different html page.
There are two method that can be used.
UINavigationController
Delegates
From your question it seems that a UINavigationController is the best option but I will show you both.
UINavigationController
When you load your mainViewController from your app delegate your going to need to wrap it in a nav controller like so:
AppDelegate.h
#property (strong, nonatomic) UINavigationController *navController;
AppDelegate.m
#synthesize navController = _navController;
//in didFinishLaunchingWithOptions:
UIViewController *mainViewController = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
navController = [[UINavigationController alloc] initWithRootViewController:mainViewController];
self.window.rootViewController = nav1;
[self.window makeKeyAndVisible];
Now in your MainViewController you have the convince of UINavigationController.
When you want to push to a child from a parent you can simply do:
ChildViewController *child = [[ChildViewController alloc]...];
[self.navigationController pushViewController:child animated:YES];
If you in your ChildViewController and want to go back simply do:
[self.navigationController popViewControllerAnimated:YES];
This is the "Drill Down" technique.
(I know "Drill Down" has more meaning than simply that but it provides a good frame of reference.)
Delegate
Now the other method that you have is to setup delegates between the classes. So if your in childView and need to call your parent, you will have a channel to do so.
In your MainViewController.h setup it like so:
#import <UIKit/UIKit.h>
//This is our delegate
#protocol TalkToParentDelegate <NSObject>
//This is our delegate method
- (void)helloParent;
#end
#interface MainViewController : UIViewController <TalkToParentDelegate>
...
..
#end
In your MainViewController.m make sure add the delegate method.
- (void)helloParent {
NSLog(#"Hello child, let me do something here");
}
In your ChildViewController.h setup it like so:
#import <UIKit/UIKit.h>
//Add header of class where protocol was defined
#import "MainViewController.h"
#interface ChildViewController : UIViewController
//Create a property we can set to reference back to our parent
#property (strong, nonatomic) id <TalkToParentDelegate> delegate;
#end
Now, in your MainViewController.m , whenever you present your ChildViewController do this:
ChildViewController *child = [[ChildViewController alloc]...];
//Set the delegate reference to parent
child.delegate = self;
//present the view
Last but not least, no when you in your child you can call methods on your parent (MainViewController) like so:
[self.delegate helloParent];
So here are two methods that you can use.
I would like to note however, you can use these together. Say you had a UINavigationController but still needed a child to talk to its parent, you can setup a delegate so that's possible.
Hope this helps.