Monday, June 25, 2018

The dangerous UIView

The dangerous UIView



I dont even know how many times I was struggling with UIView. The thing is, thats normal, I mean the complexity it carries. Its not a procedural model, its all threaded and asynchron at the backend.


Usually the problem is that you dont have the UIView actually at the point of the interaction. The mistake I did several times was the following. I had a referenced UIView instance on the main XIB file of the UIViewController:

#import <UIKit/UIKit.h>

@interface MyUIViewController

@property (nonatomic, retain) IBOutlet UIView *myView;

@end


Then in the implementation file I tried to access it and do something:

#import "MyUIViewController.h"

@implementation MyUIViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[self.myView setBackgroundColor:[UIColor redColor]];
}
return self;
}

@end


Why no effect? Because at this point the view object is not initialized. I guess its the NSCoder (not sure at all) that responsible to put together the UIViewController and the referenced NIB file. So it assigns the view object to the instance variable, but its not initialized yet. The correct way of doing it is to put it to the viewDidLoad call:

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.

[self.myView setBackgroundColor:[UIColor redColor]];
}


Todays lesson was not to transfer UIView directly. On one of my view Im adding a new subview, but only on certain actions, so its not necessary to keep it together, its enough to bundle it and create one when necessary. So as a good boy I added the property to the header:

#import <UIKit/UIKit.h>

@interface MyUIViewController {
UIView *subView;
}

@end


And initialized when it was the right time:

- (void)togglePanel {
if (self->subView == nil) {
self->subView = [[[MySubViewController alloc] initWithNibName:@"MySubView" bundle:nil] view];
[self.view addSubview:self->subView];
}
}


The funny thing is that its there, and almost functioning. I could toggle it and see just fine. However when did any interaction with event handling it failed with BAD EXEC. It took me a while till I figured out Im passing an empty view object at that point, which obviously wont lead to any fun. The proper way is to use the controller and access the view afterwards:

#import <UIKit/UIKit.h>

@interface MyUIViewController {
UIViewController *subViewController;
}

@end


- (void)togglePanel {
if (self->subViewController == nil) {
self->subViewController = [[MySubViewController alloc] initWithNibName:@"MySubView" bundle:nil];
[self.view addSubview:self->subViewController.view];
}
}


Yeah, just never trust in UIView.

---

Peter

go to link download