Question

I need a ViewController to be called modally to show some UIButton and other UIView on top of the current window. I want the background to be partially transparent and showing the current window below it - something similar to a UIActionSheet but with a custom design. I coded my VC to do the following: 1) during init the VC sets self.view.frame equals to [[UIApplication sharedApplication]keyWindow].frame 2) when show() is called the VC adds self.view on top of [[UIApplication sharedApplication]keyWindow] subViews 3) when an internal button calls the private method release() the VC remove self.view from its superview. Example with a single release button as follows:

@implementation ModalController

- (id)init
{
   self = [super init];
   if (self){
       //set my view frame equal to the keyWindow frame
       self.view.frame = [[UIApplication sharedApplication]keyWindow].frame;
       self.view.backgroundColor = [UIColor colorWithWhite:0.3f alpha:0.5f];

       //create a button to release the current VC with the size of the entire view
       UIButton *releaseMyselfButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
       [releaseMyselfButton setTitle:@"Release" forState:UIControlStateNormal];
       releaseMyselfButton.frame = CGRectMake(0, 0, 90, 20);
       [releaseMyselfButton addTarget:self action:@selector(releaseMyself) forControlEvents:UIControlEventTouchDown];

       //add the button to the view
       [self.view addSubview:releaseMyself];
   }
   return self;
}

- (void) show
{
   //add self.view to the keyWindow to make sure that it will appear on top of everything else
   [[[UIApplication sharedApplication]keyWindow] addSubview:self.view];
}

- (void)releaseMyself
{
    [self.view removeFromSuperview];
}

@end

If I create an instance of ModalController from another VC and I call show() everything goes as expected:

@interface CurrentVC ()
   @property (strong, nonatomic) ModalController *myModalController;
@end

@implementation CurrentVC
   - (void)viewDidLoad
   {
      [super viewDidLoad];
      self.myModalController = [[ModalController alloc]init];
      [self.myModalController show];
   }
@end

To make it work I need to retain the ModalController in a property until release () is called. However I would like to have the same freedom I have with UIActionSheet and simply keep an instance of it in a local variable:

@implementation CurrentVC
   - (void)viewDidLoad
   {
      [super viewDidLoad];
      ModalController *myModalController = [[ModalController alloc]init];
      [myModalController show];
   }
@end

If I do this with the current code ARC will release myModalController straight after show() is called and the release button will be pointing to nil. How can I make this work without storing the object in a property? I've identified a work around but I'm not sure it's a good design option:

@interface ModalController ()
   @property (strong, nonatomic) ModalController *myselfToAutorelease;

@implementation ModalController

- (id)init
{
   self = [super init];
   if (self){
       ... ... ...
       self.myselfToAutorelease = self;
   }
   return self;
}

- (void) show
{
   ... ... ...
}

- (void)releaseMyself
{
    [self.view removeFromSuperview];
    self.myselfToAutorelease = nil;
}

What I've done is making ModalController "self sufficient" - it stores a pointer to itself during init and set it to nil when it's ready to release himself. It works but I have the feeling that this is against the ARC design principles! Is this approach correct? If not, how can I handle this differently?

Thanks in advance for your help.

Was it helpful?

Solution

Doesn't work like that. You don't keep a reference to self. In the main view controller you just create your object. If you need it to be around longer keep it in a property in the main view controller , when done, set the property to nil in the main view controller.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top