Immediately starting new UIViewController from a viewcontroller - objective-c

When the UIViewController starts, I want to start another UIViewController immediately.
This doesn't work:
-(void) awakeFromNib {
UIViewController *newcontroller = [[[UIViewController alloc] init] autorelease];
...
[self presentModalViewController:newcontroller animated:YES];
}
In order for this to work, I have to do afterDelay for a method, like so:
-(void) awakeFromNib {
[self performSelector:#selector(startNewController) withObject:nil afterDelay:0.5];
[super init];
}
-(void) startNewController {
UIViewController *newcontroller = [[[UIViewController alloc] init] autorelease];
...
}
Is it possible to get it to work without delay?

Call startNewController in your viewDidAppear method instead, that happens because your viewController is not totally loaded when you try to present the modal viewController, so that's why it works when you wait.

Practically, you should not plan your application architecture which forces you to do such implementations. Though, I can understand there are times where you have no way out..
I'd say:
best solution for your case is to call your controller from
viewDidAppear
or
viewWillAppear

Related

What common ways are there to release persistent memory usage not released by ARC?

As I move from one viewcontroller to another (containing images, a scrollview, labels and other stuf) my persistent is not released.
In instruments it currently looks like this:
Facts:
I'm using Objective-C, ARC and Auto Layout
My "- (void)dealloc{ }" is being called but there is nothing in it
NSZombie is not enabled
I have tried:
Replacing all occurrences of self with weakSelf
typeof(self) __weak weakSelf = self;
I use imageWithContentsOfFile not imageNamed
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"thumbUp" ofType:#"png"]]
not
[UIImage imageNamed:#"thumbUp.png"]
In "-(void)viewDidDisappear:(BOOL)animated" I have:
Invalidate all timers
[_searchAnimationTimer invalidate];
Setting all stuff to nil (every object and variable)
_searchAnimationTimer = nil;
Removing observers
[[NSNotificationCenter defaultCenter] removeObserver:weakSelf]
Setting all delegates to nil
[self.tableView setDelegate:nil];
Setting all data sources to nil
[self.tableView setDataSource:nil];
I've added [super viewDidDisappear:(BOOL)animated]; in the end of "-(void)viewDidDisappear:(BOOL)animated"
-(void)viewDidDisappear:(BOOL)animated{
//Code here
[super viewDidDisappear:(BOOL)animated];
}
In "- (void)viewDidLoad" I:
Dismiss ViewControllers using both
[weakSelf.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];
and
_mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
_vc = [_mainStoryboard instantiateViewControllerWithIdentifier:#"Omraden"];
[_vc dismissViewControllerAnimated:NO completion:^{ }];
In .h I have:
I have created an IBOutlet for all objects in storyboard.
And set all #property to weak
#property (weak, nonatomic) IBOutlet UIView *contentView;
Whats my next step? What common changes can I do? I'm new at memory management. Need more info? I'll answer fast :)
List of solutions so far:
In "-(void)viewDidDisappear:(BOOL)animated", also set the image of every UIimageView to nil like this:
_someImageView.image = nil;
I also added this:
for (CALayer* layer in [weakSelf.view.layer sublayers])
{
[layer removeAllAnimations];
}
Started using #autoreleasepool inside for-statements (not sure where else to use it)
#autoreleasepool{
//code
}

UIWebViewDelegate functions have not been called

.h file:
#interface MyView: UIViewController <UIWebViewDelegate> {
UIWebView *webView;
}
.m file:
-(void)viewDidLoad {
CGRect webFrame = [[UIScreen mainScreen] applicationFrame];
webView= [[UIWebView alloc] initWithFrame:webFrame];
webView.delegate = self;
[self.view addSubview:webView];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com"]]];
}
-(void)webViewDidStartLoad:(UIWebView *)webView {
NSLog(#"start");
}
-(void)webViewDidFinishLoad:(UIWebView *)webView {
NSLog(#"finish");
}
-(void)dealloc {
webView.delegate = nil;
webView = nil;
}
create MyView in another ViewController:
MyView * myView = [[MyView alloc] init];
[self.view addSubView:myView.view];
myView = nil;
myView is set to be nil so its delegate is also destroyed.
To solve this, remove the sentence of myView = nil.
Thank you guys who answered me. I did learnt from your answers.
As srikanth said myview is a controller and it needs to be told its on screen and retained so it doesnt go away AND that is your immediate the real issue in your case (I think). Nobody retains myView.
make it a member variable so it isnt released directly after it gave you its view :).
#interface MyCallerWithDoesTheASI : NSObject {
MyView *myView;
}
#end
or do it right and add it like srikanth said ::
[self addChildViewController:myView];
[self.view addSubview:myView.view];
[myView didMoveToParentViewController:self];
or for example and present myView modal
[self presentViewController:myView animated:NO completion:^{ [[myView dismiss...]; }
MyView is a view controller. And you are treating it like a view, in the second case. If you want to add a view of a view controller directly, it will not get all of the view controller methods called. To be able to get the correct functionality, you will have to do some thing different.
Assuming you are in another view controller then in the other view controller, when ever you want to add the view of MyView view controller, do the following
[self addChildViewController:myView];
[self.view addSubview:myView.view];
[myView didMoveToParentViewController:self];
But even before doing that, please use correct naming convention. If you are naming a subclass of UIViewController as MyView, you will confuse yourself. Name it as MyViewController. That way, you will be able to keep track of stuff better.
Read more about view controller containment for your problem.

UIImagePickerController Freezes when camera flips

My UIImagePickerController freezes and the camera closes when the button to flip the camera from front to back is pressed. This is how I initialize the image picker controller object within the project (the rest of the code was ommitted) from the methods as it is irrelevant to the UIimagepickercontroller object.
//In my .h file
UIImagePickerController * imgPicker;
//in my .m file
-(void)viewDidLoad {
imgPicker = [[UIImagePickerController alloc] init];
imgPicker.delegate = self;
imgPicker.allowsEditing = YES;
}
-(void) takePicture {
imgPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:imgPicker animated:YES completion:NULL];
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
masterImage.image = [info objectForKey:UIImagePickerControllerEditedImage];
if(masterImage.image == nil) {
masterImage.image = [info objectForKey:UIImagePickerControllerEditedImage];
}
[self dismissModalViewControllerAnimated:YES];
}
-(void) imagePickerControllerDidCancel:(UIImagePickerController *)picker{
[self dismissModalViewControllerAnimated:YES];
}
-(void) releaseOutlets {
[imgPicker release];
}
Just for rule, change your code. Instead of:
UIImagePickerController * imgPicker;
Write in your .h file:
#property (nonatomic, strong) UIImagePickerController * imgPicker;
than synthesize it in your .m file:
imgPicker = _imgPicker;
and next every call to this property call with self.
first of all, you should not alloc init in viewdidload method. Do all ur allocations in -init method.
add property as suggested by edzio27.
test again
if problem persists:
- check if u are "receiving memory warning". In case of memory warning ur viewdidload method is called again. In case u keep ur alloc init in that method u will be creating new instance everytime.
We faced a similar issue with MPMoviePlayerController. not sure if u have the same issue.

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

Calling SEL from parentViewController in iOS

I have a ViewController in which I create a Modal ViewController. I have a SEL value in my modal that I set when it is being instantiated from the parent.
setDateViewController.selectorName = #selector(myMethod:);
In my modal I am trying to call this SEL like:
[[self parentViewController] performSelector:self.selectorName withObject:selectedDate afterDelay:.5];
{selectedDate} is obviously a value from my modal.
I don't get any errors or stack, however, this SEL (method) on my parent is never being called. For some reason I think this should work, but something tells me I'm way off track.
Thanks.
I guess [self parentviewcontroller] is not returning anything.
Try UiviewController* v = [self parentviewcontroller]; and check if is nil. Most probably it should be nil. Else if its was pointing to another object of different class then it would have crashed. Please do one thing. YOu should set bot the object and the methd you need to call. IT will solve any issues if it has any.
setDateViewController.selectorDelegate = self;
setDateViewController.selectorName = #selector(myMethod:);
call like this from parent class. So you can dynamically specify the method and the object you want to call gives more flexibility.
and use,
[selectorDelegate performSelector:self.selectorName withObject:selectedDate afterDelay:.5];
this should solve any issues.
Perhaps you would consider added a delegate protocol to your modal that will allow it to call the method on the parent.
Quick (untested) example:
// MyController.h
#protocol MyControllerDelegate;
#interface MyController : UIViewController
{
id<MyControllerDelegate> delegate;
}
#end
#protocol MyControllerDelegate <NSObject>
- (void)methodToCall:(id)sender;
#end
// MyControler.m
#implementation MyController
- (void) loadView
{
[super loadView];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(20.0f, 20.0f, 50.0f, 30.0f);
[btn setTitle:#"blah" forState:UIControlStateNormal];
[btn addTarget:self.delegate
action:#selector(methodToCall:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
#end
// ParentController.h
#interface ParentController : UIViewController<MyControllerDelegate>
{
}
#end
// ParentController.m
#implementation ParentController
- (void)methodToCall:(id)sender
{
NSLog(#"HERE");
}
#end
Just make sure when you are creating your modal controller you set it's delegate to self on the parent:
MyController *controller = [[MyController alloc] init];
controller.delegate = self;
[self presentModalViewController:controller animated:YES];