UILabel only shows up when placed in viewDidAppear of viewcontroller - ios

I can't figure out why a UILabel only shows up when I create it from the viewDidAppear within my viewController. Here is my code so far:
Within AppDelegate:
CGRect viewBounds;
viewBounds.origin.x = 0;
viewBounds.origin.y = 0;
viewBounds.size.width = screenBounds.size.height;
viewBounds.size.height = screenBounds.size.width;
view = [[EAGLView alloc] initWithFrame: viewBounds];
overlayView = [[OverlayView alloc] initWithFrame: screenBounds];
overlayViewController = [[OverlayViewController alloc] init];
[overlayViewController setView:overlayView];
[window addSubview:view];
[window addSubview: overlayViewController.view];
[window makeKeyAndVisible];
[view start];
Within overlayViewController: (This function is successfully called, but the UILabel doesn't show up)
-(void)showText
{
NSLog(#"showText()");
textLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 300.0f, 300.0f)];
textLabel.textColor = [UIColor whiteColor];
textLabel.backgroundColor = [UIColor clearColor];
textLabel.textAlignment = UITextAlignmentCenter;
textLabel.font = [UIFont fontWithName:#"Arial" size:30];
textLabel.text = [NSString stringWithFormat:#"TESTING!"];
[self.view addSubview:textLabel];
[self.view bringSubviewToFront:textLabel];
}
Within overlayViewController: (Placing the above code into the viewDidAppear makes it show up from the beginning)
-(void)viewDidAppear:(BOOL)animated
{
textLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 300.0f, 300.0f)];
textLabel.textColor = [UIColor whiteColor];
textLabel.backgroundColor = [UIColor clearColor];
textLabel.textAlignment = UITextAlignmentCenter;
textLabel.font = [UIFont fontWithName:#"Arial" size:30];
textLabel.text = [NSString stringWithFormat:#"TESTING!"];
[self.view addSubview:textLabel];
[self.view bringSubviewToFront:textLabel];
[super viewDidAppear:animated];
}
Why would the UILabel not show up from within showText() function when it's called? I verified that the NSLog outputs to the console, yet the UILabel is not on the screen.
To give a little more context, this is an AR application. There is an EAGLView showing the feed of the camera on the screen. As I said, the UILabel, when placed in the viewDidLoad of overlayViewController, shows up the moment the app launches above the camera video feed. When placed inside the showText function, the UILabel doesn't show.
Any help would be appreciated! Thank you!
PS. To give more information, I have tried calling showText() in two ways:
Within my EAGLView.mm (which is where most of the AR functions are handled), I setup a notification as such:
[[NSNotificationCenter defaultCenter] postNotificationName:#"showTextOverlay" object:nil];
Then, within OverlayViewController.m, I placed an observer within ViewDidAppear (since ViewDidLoad doesn't seem to get called, but ViewDidAppear does...)
-(void)viewDidAppear:(BOOL)animated
{
NSLog(#"viewDidAppear");
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(showText)
name:#"showTextOverlay"
object:nil];
[super viewDidAppear:animated];
}
The selector of this observer calls showText(), which is also inside of OverlayViewController.
I next tried a second way:
Within EAGLView.mm, I got the application delegate and controllers directly as such:
ImageTargetsAppDelegate *delegate = (ImageTargetsAppDelegate *)[UIApplication sharedApplication].delegate;
OverlayViewController *controller = delegate.overlayViewController;
[controller showText];
But both ways still did not show any UILabel...
ANSWERED:
I figured this out. It turns out that the way the sample application is written, the updates to UIKit were not being called on the main thread. Therefore, I used the performSelectorOnMainThread when calling my showText...
Thank you everyone for your help!

One thing to think about is that showText ends with these lines:
[self.view addSubview:textLabel];
[self.view bringSubviewToFront:textLabel];
and then the next line is:
[overlayViewController setView:overlayView];
So, what would the value of self.view be in showText if the viewController does even set its view until the next line? You are likely adding a subview to a nil object.
Generally speaking, you should be doing things a little bit differently. The designated initializer for a view controller is initWithNibName:bundle rather than init so it is recommended that you use that.
More importantly, the OverlayViewController should either load its view from a .xib file or implement the loadView method to create its view. If you add the label inside of that method or in one of the methods called after it, like viewDidLoad, you will see the label.

Related

Is there a way to call the subview of a view controller's self.view in a function outside of viewDidLoad?

Essentially what I'm trying to do here is have a function which sets the alpha of a subview of self.view to 1 (it is hidden by default) which gets called upon pressing a button. i've run into this problem a few times because i declare subviews in viewDidLoad and i don't know of a way to interact with those in a different function (i've tried self.view.subviews[n] but xcode is not happy with that). the only other way i can think of to make this happen is to set self.view equal to the view i want, or maybe even create the view within the function i'm hoping to call with the button (the issue i see with that is potentially the view will not overlay the button, which i want to happen).
here's what i have so far:
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIView *firstBackground = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIView *blackOverlay = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
blackOverlay.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.0];
firstBackground.backgroundColor = [UIColor whiteColor];
UIButton *fakeNotifButton = [UIButton buttonWithType:UIButtonTypeCustom];
[fakeNotifButton addTarget:blackOverlay action:#selector(setupFakeNotifScreen:) forControlEvents:UIControlEventTouchUpInside];
//i haven't finished the button yet, that i don't need any help with
}
-(IBAction)setupFakeNotifScreen:(id)sender {
[UIView animateWithDuration:1.0
delay:0.5
options:UIViewAnimationOptionCurveEaseInOut
animations:^{view = 1.0;} //here is where i want to call blackOverlay
completion:^(BOOL finished){}];
}
#end
edit: i figured it out... didn't even need the blackOverlay view. here's the solution for any future google people... there are probably more efficient ways to do this so i would appreciate anybody who's better than me weighing in:
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *fakeNotifButton = [UIButton buttonWithType:UIButtonTypeCustom];
[fakeNotifButton addTarget:self action:#selector(setupFakeNotifScreen:) forControlEvents:UIControlEventTouchUpInside];
fakeNotifButton.frame = CGRectMake(([UIScreen mainScreen].bounds.size.width/2) - 80, 300, 160, 40);
[fakeNotifButton setTitle:#"test" forState:UIControlStateNormal];
[fakeNotifButton setBackgroundColor:[UIColor systemGreenColor]];
fakeNotifButton.layer.cornerCurve = #"continuous";
fakeNotifButton.layer.cornerRadius = 15;
[self.view addSubview:fakeNotifButton];
}
-(void)setupFakeNotifScreen:(UIButton *)sender {
[UIView animateWithDuration:0.2
delay:0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{self.view.backgroundColor = [UIColor blackColor]; sender.alpha = 0.0;}
completion:^(BOOL finished){}];
}
#end
When you declare
UIView *blackOverlay = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
...that reference is inside the method viewDidLoad, so its existence is confined to that method. It is visible only inside the method, and indeed the reference goes out of existence when the method ends. (The view itself also goes out of existence; you have not put it into the interface.)
If you want a persistent reference to this view, you need to declare a property (or at least an instance variable, aka iva), and set it to this view. You still won't be able to do anything visible with the view if you don't actually put it into the interface.

Changing NavigationItem Title in viewDidAppear in iOS

I've set the NavigationItem.title in Interface builder for readability but in code i need to do
self.navigationItem.title = SomeThingThatComesFromDB
I've Tried to do this in viewDidLoad and viewDidAppear but in first app launching the title is still the thing that I've set in interface builder.
How I can fix this?
This is my root view controller for application launch and here is the code that I'm using:
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
for (Branch *b in [UserManager sharedInstance].branches) {
if ([b.branchId isEqualToString: [UserManager sharedInstance].vendorId]) {
self.title = b.branchName;
}
}
}
You got the following comparison in place to set/update the navigation item's title.
if ([b.branchId isEqualToString: [UserManager sharedInstance].vendorId]) {
self.title = b.branchName;
}
Problem seems to be that the [UserManager sharedInstance].vendorId] variable is not set (yet), when you call the function to update a navigation item's title. As you are able to set it correctly, after the view had disappeared and appeared back again.
The below code illustrates once again how one can set a navigation item's title, as you also did:
If you want to update the title in general for all related navigation elements (UITabbarController tabs, UINavigationController back button etc.) simply use:
self.navigationItem.title = SomeThingThatComesFromDB
https://developer.apple.com/reference/uikit/uiviewcontroller/1621364-title
If you got a dedicated navigation item in your UINavigationController's bar, you could access it the following way (make sure, there is only one to access)
self.navigationItem.rightBarButtonItem.title = SomeThingThatComesFromDB
self.navigationItem.leftBarButtonItem.title = SomeThingThatComesFromDB
Try out below code:
CGRect rect = self.navigationController.navigationBar.frame;
UIView *myView = [[UIView alloc] init];
UILabel *title = [[UILabel alloc] init];
[title setFont:[UIFont systemFontOfSize:18.0]];
title.text = *SomeThingThatComesFromDB*;
title.textColor = [UIColor whiteColor];
CGSize size = [title.text sizeWithAttributes:
#{NSFontAttributeName:
title.font}];
title.frame = CGRectMake(20, 0, size.width, rect.size.height);//40
myView.frame = CGRectMake(0, 0, 40+size.width, rect.size.height);
[myView addSubview:title];
self.navigationItem.titleView = myView;

Zooming within UIWebView crashes app

I've looked at 20+ different posts that are vaguely related to this and haven't been able to find a solution.
What I have is a class which subclasses UIViewController. On this class's loadView method, I'm adding a UIWebView inside of a UIScrollView. The UIWebView has scalesPageToFit set to YES. The problem I'm facing is that it seems like zooms are being multiplied! i.e. When you zoom inside the web view the very first time, everything seems to work properly. When you zoom AGAIN, it seems that it takes your already zoomed version and tries to amplify that by an additional factor. This causes the app to crash. Any thoughts on how to fix this? I think something about the reported zoomScale from the UIWebView is messing things up.
Here's a modified sample code to get an idea of the current implementation:
# This is a UIViewController
#implementation MyViewController
- (void)loadView
{
[super loadView];
self.view.accessibilityLabel = #"MyView";
self.scrollView = [[UIScrollView alloc] init];
self.scrollView.backgroundColor = [UIColor blueColor];
self.scrollView.scrollsToTop = YES;
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.scrollView];
// constraints removed from sample for readability
self.headerView = [[UIViewController alloc] init];
[self.scrollView addSubview:self.headerView];
self.bodyView = [[UIWebView alloc] init];
self.bodyView.delegate = self;
self.bodyView.scalesPageToFit = YES;
self.bodyView.scrollView.scrollsToTop = NO;
self.bodyView.translatesAutoresizingMaskIntoConstraints = NO;
[self.bodyView.scrollView addObserver:self
forKeyPath:KeyValuePath
options:NSKeyValueObservingOptionNew
context:nil];
[self.scrollView addSubview:self.bodyView];
// other constraints here
}
Any help or feedback would be immensely appreciated.

Correctly remove object (with code example) iOS

Does the following code (removeViews) correctly remove the reference to the objects, i.e delete them, so I do not keep making more Views when the method createViews is called. createViews creates the views and removeViews sets them to nil. Note: this is a very simple example to enhance understanding, and serves no actual purpose.
-(void) createViews{
UITableView * tableView = [[UITableView alloc] initWithFrame:CGRectMake(0,0,200,200)];
tableView.delegate=self;
tableView.datasource = self;
self.mainTableView = tableView;//self.mainTableView is a weak reference
[self.view.superView addSubview: self.mainTableView];
UIView * view = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,400)];
view.backgroundColor = [UIColor redColor];
self.mainView = view;//self.mainView is a strong reference
[self.view.superView addSubviews:self.mainView];
}
-(void) removeViews{
self.mainView = nil;
self.mainTableView=nil;
}
First remove them from their superView and then set them to nil
-(void) removeViews{
[self.mainView removeFromSuperview];
[self.mainTableView removeFromSuperview];
self.mainView = nil;
self.mainTableView=nil;
}

Toolbar items dissapear when view changed with UIActionSheet

When initiating a view from a UIActionSheet button, upon returning to the view via the navigationBar back button, the toolbar while still visible does not have any of the buttons that were previously on it. This error has arisen since updating to iOS 6 and occurs while testing it on the simulator and a device running iOS 6 only. If I comment out the code that hides the toolbar on the view pushed by the UIActionSheet the buttons are added when going back.
I'm making my toolbar items programatically in viewWillAppear and showing the UIActionSheet from the toolbar which I'm accessing via self.navigationController.toolbar.
Any idea what is causing this problem? It's only happened since iOS 6 has come around so is there any changes that I need to take into account regarding viewWillAppear?
This is how the view is pushed from the actionSheet:
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (actionSheet.tag == 2) {
if (buttonIndex == 0) {
[self dismissAllTips];
self.actionNoteAddView= [[self.storyboard instantiateViewControllerWithIdentifier:#"IDActionNoteAddView"] retain];
actionNoteAddView.note_id = 0;
actionNoteAddView.iscompleted=0;
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"tool_tips"];
[self.navigationController pushViewController:actionNoteAddView animated:TRUE];
[actionNoteAddView release];
}else if(buttonIndex == 1){
...
These are the view methods for the pushed view:
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.navigationItem.hidesBackButton = NO;
[self.navigationController setToolbarHidden:YES];
txtcontent.layer.cornerRadius = 10.0f;
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
}
These are the view methods for the view that pushed the view using the actionSheet:
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.navigationItem.hidesBackButton = YES;
[self.navigationController setToolbarHidden:NO];
self.navigationController.navigationBarHidden=NO;
self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque;
self.navigationController.navigationBar.tintColor = [UIColor colorWithRed:0.8 green:0.45 blue:0.2 alpha:1];
self.navigationController.toolbar.barStyle = UIBarStyleBlackOpaque;
self.navigationController.toolbar.tintColor = [UIColor colorWithRed:0.8 green:0.45 blue:0.2 alpha:1];
UIImage *actionButtonImage = [UIImage imageNamed:#"31-circle-plus#2x.png"];
UIBarButtonItem *actionButton = [[UIBarButtonItem alloc] initWithImage:actionButtonImage style:UIBarButtonItemStylePlain target:self action:#selector(actionPressed:)
];
UIImage *dashButtonImage = [UIImage imageNamed:#"19-gear.png"];
UIBarButtonItem *dashButton = [[UIBarButtonItem alloc] initWithImage:dashButtonImage style:UIBarButtonItemStylePlain target:self action:#selector(settingsPressed:)];
UIBarButtonItem *flexItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
target:nil
action:nil];
NSArray *toolitems = [NSArray arrayWithObjects:dashButton, flexItem, actionButton, flexItem, nil];
[self setToolbarItems:toolitems];
self.title = #"Dashboard";
defaultProfile.text = [[NSUserDefaults standardUserDefaults] stringForKey:#"default_profile"];
BOOL dailyProcess = [[NSUserDefaults standardUserDefaults] boolForKey:#"daily_process"];
if(dailyProcess){
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"daily_process"];
[[NSUserDefaults standardUserDefaults] synchronize];
loading = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
labelProcess = [[UILabel alloc]initWithFrame:CGRectMake(60, 105, 240, 30)];
labelProcess.text = #"Processing...";
labelProcess.backgroundColor = [UIColor clearColor];
labelProcess.textColor=[UIColor colorWithRed:0.8 green:0.45 blue:0.2 alpha:1];
[labelProcess setFont:[UIFont systemFontOfSize:20]];
loading.opaque = NO;
loading.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.6f];
indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[indicator setHidesWhenStopped:YES];
indicator.center = self.view.center;
[self.view addSubview:loading];
[self.view addSubview:indicator];
[self.view addSubview:labelProcess];
[indicator startAnimating];
}
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
CGRect frame = CGRectMake(157, 365, 10, 10);
UIView *viewToPointAt = [[UIView alloc] initWithFrame:frame];
[self.view addSubview:viewToPointAt];
BOOL willies = [[NSUserDefaults standardUserDefaults] boolForKey:#"tool_tips"];
if(willies==YES){
if(popTip == nil) {
popTip = [[[CMPopTipView alloc] initWithMessage:#"Step 1/3: This is the Action Button. You can create, view and auto-fill notes which are then added to your timeline.(Click for step 2)."] autorelease];
popTip.delegate = self;
[popTip presentPointingAtView:viewToPointAt inView:self.view animated:YES];
popTip.backgroundColor = [UIColor colorWithRed:0.8 green:0.45 blue:0.2 alpha:1];
popTip.textColor = [UIColor whiteColor];
}
}
[viewToPointAt release];
}
Tried a lot of different techniques and eventually sorted it by showing it in one view method and hiding it in the next. It's one fo the strangest bugs I have encountered and this is hardly a fix, but I hate having unanswered questions.
You may solve this by hiding the toolbar in the next view, but that is not a very good solution, as other views that can be possibly opened from the view that contains the toolbar will all have to hide the toolbar when needed, this is annoying.
Another solution is to hide the toolbar in viewDidDisappear but there is another problem, let's say another new view needs the toolbar as well, and it sets the toolbar visible in its own viewWillAppear then the problem is that the viewWillAppear for the new view will be called actually before viewDidDisappear of the previous view, so in that case the toolbar disappear even the new view desires it.
Anyway, I'm not sure if this is a bug of iOS6 as it works fine for iOS5, what worked for me was to wrap the code that opens the new view into dispatch_async(dispatch_queue_t queue, dispatch_block_t block), my understanding is that by doing this the action sheet will be dismissed before the new view is shown as you put the code that opens the new view to the end of the main queue(like what we did for viewDidDisappear, but this happens before the call to viewWillAppear of next view so it works perfect).
Got the solution, and I think it is an Apple bug in iOS 6.0 and above.
In the NavigationController view stack if any view hides the toolbar, e.g. self.navigationController.toolbarHidden = YES, then since that point on all the Views that had already created a toolBar with buttons, will loose the buttons.
So, my solution to this problem was to keep the toolBar in all the Views(had to compromise on the UI, but in my app pikSpeak, the functionality was very important.)
This is an ancient thread, I know, but I just recently ran into this problem. The clue to my solution was that some delay was needed between pushing a new view and closing the action sheet. I changed from using clickedButtonAtIndex to didDismissWithButtonIndex so that the push would occur after the action sheet was gone. Problem solved!

Resources