Creating uiviewcontroller as weak programmatically - ios

I am creating uiviewcontroller in my one of the singleton like this.
BrowserVC *vc = [BrowserVC loadFromNib];
vc.titleName = #"Password Management";
[vc setData:#{#"url":url.absoluteString}];
vc.successBlock = ^(NSString *urlStr){
if (![urlStr isEqualToString:url.absoluteString])
[vc dismissViewControllerAnimated:YES completion:nil];
};
Then, I got this usual error.
Capturing 'vc' strongly in this block is likely to lead a retain
cycle.
To solve that warning, I have used either __Weak or __unsafe_unretained. Now, problem come in. My vc is released immediately after I initiate. I can't even set titleName. How shall I do?

The pattern is this
BrowserVC *vc = [BrowserVC loadFromNib];
vc.titleName = #"Password Management";
[vc setData:#{#"url":url.absoluteString}];
__weak __typeof(vc) weakVC = vc;
vc.successBlock = ^(NSString *urlStr){
__typeof(vc) strongVC = weakVC;
if (strongVC && ![urlStr isEqualToString:url.absoluteString])
[strongVC dismissViewControllerAnimated:YES completion:nil];
};
You create the view controller as you normally would but then you create a weak reference to the view controller and pass that into the block

Related

how to add New UIViewCOntroller Over UiView

I have added subview in a UIViewController and I want a new UIViewController Should be loaded on click of button.
Challenge is I am not able to use button in new UIViewController.
Code which I have write:
DetailsOfDayViewController *aViewController =[[DetailsOfDayViewController alloc] initWithNibName:#"DetailsOfDayViewController" bundle:nil];
aViewController.dateParsing = dateparsing;
[self addSubview:aViewController.view];
This will fix your issue. This is happening because your view controller is being deallocated when you don't have any strong pointers on it.
DetailsOfDayViewController *aViewController =[[DetailsOfDayViewController alloc] initWithNibName:#"DetailsOfDayViewController" bundle:nil];
aViewController.dateParsing = dateparsing;
[self addChildViewController:aViewController];
[self addSubview:aViewController.view];
Another fix will be connecting this view controller to a property:
#property(nonatomic,strong) DetailsOfDayViewController *aViewController;
And change your code like this:
self.aViewController = [[DetailsOfDayViewController alloc] initWithNibName:#"DetailsOfDayViewController" bundle:nil];
self.aViewController.dateParsing = dateparsing;
[self addSubview:self.aViewController.view];
For showing another controller you can following options
1. Add SubView
newViewControllerObj.view.frame = oldViewControllerObj(self).view.frame
[oldViewControllerObj(self).view.newViewControllerObj.view];
2. Present
[oldViewControllerObj(self) presentViewController: newViewControllerObj animated:YES completion:nil];
3. Push using Navigation (For this you already have to set navigation controller as root controller)
[oldViewControllerObj(self).navigationController pushViewController:newViewControllerObj animated:YES];

Present View Controller from another class

I am trying to present a new viewcontroller from a class outside of that viewcontroller.
It looks like this:
AppDelegate.m -> inside has this code:
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
Now, inside of that method is an object which utilises another class: [actionSheet launchActionSheetNav]; this simply makes an actionsheet appear with different options.
Now, inside of ActionSheets.m is some code, involving a segue as follows:
handler:^(AHKActionSheet *as){
ViewControllerYoutube *vc = [[ViewControllerYoutube alloc]init];
[vc presentViewController:vc animated:YES completion:nil];
}];
All I want to do, is launch a new view controller from inside of there, however doing [self.navigationController brings an error that ActionSheets.m does not contain such method/property.
How can I present a viewcontroller from outside the original classes?
So the hierarchy is as follows:
Viewing Storyboard > Listening on AppDelegate.m > Inside that, a class method is called which takes you to ActionSheets.m -> and from there I need to display the new viewcontroller.
This line:
ViewControllerYoutube *vc = [[ViewControllerYoutube alloc]init];
Creates a new instance of ViewControllerYoutube. This ViewController doesn't exist anywhere else but that line, so when you follow it with this:
ViewControllerYoutube *vc = [[ViewControllerYoutube alloc]init];
[vc presentViewController:vc animated:YES completion:nil];
You're trying to present on a view controller that hasn't yet been presented.
If you want to present from an outside class, you need some way to keep a reference to the view controller you want to present, perhaps in your ActionSheet.h
#property (weak, nonatomic) ViewControllerYoutube *myViewControllerYoutube;
Then assign it when you create your action sheet (assuming you create it in ViewControllerYoutube)
ActionSheet * myActionSheet = [[ActionSheet alloc]init];
myActionSheet.myViewControllerYoutube = self;
Then instead of this:
ViewControllerYoutube *vc = [[ViewControllerYoutube alloc]init];
[vc presentViewController:vc animated:YES completion:nil];
Call this:
[_myViewControllerYoutube presentViewController:vc animated:YES completion:nil];
UPDATE
Based on our chat, here's how I think we can solve it.
In ActionSheet.h:
#property (weak, nonatomic) UIViewController *presentingViewController;
In 'ActionSheet.m'
ViewControllerYoutube *vc = [[ViewControllerYoutube alloc]init];
[_presentingViewController presentViewController:vc animated:YES completion:nil];
In your AppDelegate:
ActionSheet * actionSheet = [[ActionSheet alloc]init];
UITabBarController * tabController = (UITabBarController *)self.window.rootViewController;
actionSheet.presentingViewController = tabController.selectedViewController;
you need to do
[currentViewController presentViewController:vc animated:YES completion:nil];
do you have any reference to "correntViewController" from this block? from this class?
if not, do this
add a property
#property(nonatomic,strong) UIViewController *currentViewController
in the given class
then in your init method, or in the usual setCurrentViewController:
pass the reference to the controller,
and change you[vc presentViewController:vc animated:YES completion:nil];
to
[self.currentViewController presentViewController:vc animated:YES completion:nil];

ViewControllers as instance variables

I have a custom ViewController which is an instance variable of my root viewController.
I intend to modally present it whenever a button is touch. Therefore the viewController will be presented and dismissed potentially many many times.
I obviously only want to alloc init my instance variable once as the modal viewController is not deallocated each time it's dismissed, so should I have code like this inside my button action to ensure that it's only alloc and inited once?:
if(!myViewController)
{
ViewController *myViewController = [[ViewController alloc] init];
}
[self presentViewController:myViewController animated:YES completion:NULL];
I usually use lazy instatiation in those cases:
Declare a property for your ViewController:
#property(nonatomic, strong) UIViewController *myViewController;
After that you can override the get of myViewController
-(UIViewController*) myViewController {
if(!_myViewController) {
_myViewController = [[UIViewController alloc] init];
}
return _myViewController;
}
This way you guarantee that was only instantiated once and is always there when you needed.
ATTENTION
This works well if you always use self.myViewController. I consider a good practice that properties' generated iVars should only be accessed in their setters/getters.
You can use the following way to ensure that only one instance of the view controller active at a time.
if(myViewController) {
[myViewController release];
myViewController = nil;
}
myViewController = [[ViewController alloc] init];
[self presentViewController:myViewController animated:YES completion:NULL];
You need to make myViewController as class variable.

dismissViewControllerAnimated prevents new UIViewController from showing

I am trying to replace one UIViewController with another, However I have ecountered a problem.
If I write this
[self dismissViewControllerAnimated:NO completion:nil];
//load currentProjectListViewController
currentProjectListViewController = [[CurrentProjectListViewController alloc] initWithNibName:#"CurrentProjectListViewController" bundle:nil];
[self presentViewController:currentProjectListViewController animated:NO completion:nil];
This almost works, however the view just blinks and nothing happens.. no new view is loaded or anything, I have put a break point inside currentProjectListViewController and the thread never makes it there.
however if I do this.
//load currentProjectListViewController
currentProjectListViewController = [[CurrentProjectListViewController alloc] initWithNibName:#"CurrentProjectListViewController" bundle:nil];
[self presentViewController:currentProjectListViewController animated:NO completion:nil];
currentProjectListViewController loads perfectly fine. however I am worried about whats hapening with the previous view? is it stuck there in memory? or is it gone?
my question is how can I dismiss it from memory as well as site without stopping my next view from appearing.
any help would be greatly appreciated.
No, the second way is the correct way as far as I see it. In the first method you're asking the VC to dismiss before a new VC is presented. This would be there is no view, which wouldn't happen.
Bu presenting a new VC, the old VC won't be retained in memory as the nature of the view is that it only uses memory when it is in view. I hope this make makes sense.
Try presenting the new view controller in the completion handler of the dismiss method call:
typeof(self) __weak weakSelf = self; //Need to have a weak reference to self to prevent retain cycle.
[self dismissViewControllerAnimated:NO completion:^{
currentProjectListViewController = [[CurrentProjectListViewController alloc] initWithNibName:#"CurrentProjectListViewController" bundle:nil];
[weakSelf presentViewController:currentProjectListViewController animated:NO completion:nil];
}];

App crashes while Modal view controller closes

I want to display the modalViewController from the 2nd screen of the app, and when I dismiss the controller it should navigate to the 1st screen. The below code works fine in iPhone 4, 5 and iPod Touch but NOT in iPAD. The objective is when I dismiss the modalViewController it shouldn't go back to the second screen, but it should display the first screen.
ShareEmail *shareEmail = [[ShareEmail alloc] initWithNibName:[NSString stringWithFormat:#"%#",xibShareEmail] bundle:nil];
shareEmail.fromWer = #"ownPer";
[self presentModalViewController:shareEmail animated:NO];
[shareEmail release];
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];
In share email class
[self dismissModalViewControllerAnimated:YES];
You need to retain your shareEmail view controller - make a synthesized retained property
YourClass.h:
#property (nonatomic, retain) ShareEmail *shareEmailViewController;
YourClass.m:
#synthesize shareEmailViewController;
Then display your modal view controller by:
ShareEmail *shareEmail = [[ShareEmail alloc] initWithNibName:[NSString stringWithFormat:#"%#",xibShareEmail] bundle:nil];
self.shareEmailViewController = shareEmail;
[self presentModalViewController:shareEmail animated:NO];
[shareEmail release];
The retained property will keep the view controller from being deallocated while in use. Then when you dismiss it later you can do:
[self.shareEmailViewController dismissModalViewControllerAnimated:YES];
self.shareEmailViewController = nil;
which will release the retained property and free the memory after you're done with it.
Something interesting is happening. You are presenting a view controller from self, and then you're having the navigationController perform its backwards navigation. At this point, the self I was talking about earlier disappears.
Remove the popViewController method from your presentViewController method.
Also, you'll need to use the ^completion handler method. That's where you should put your navigation controller pop code.
-(void)present {
ShareEmail *email = [[ShareEmail...
//You'll need to get a weak reference to `self` in `email`
email.modalDelegate = self; //you need to make a property in ShareEmail
[self presentViewController:email animated:YES completion:nil];
[email release];
}
-(void)dismiss {
[self dismissViewControllerAnimated:YES completion:nil];
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];
}
//in ShareEmail.m
[modalDelegate dismiss];

Resources