iOS: Can't show view after hiding it - ios

I have a activityIndicator and a transparent black layer behind it. When something loads I show them like this:
[activityIndicator startAnimating];
loadingCover.hidden = NO;
And when I hiden them, I just do it like this:
[activityIndicator stopAnimating]; //hides on stop
loadingCover.hidden = YES;
So far everything works. But somehow if I want to show them again, it doesn't work. Any ideas?
EDIT:
This is how I do it...
- (void)viewDidLoad {
[mainView addSubview:loadingCover]; //works
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
[loadingCover removeFromSuperview]; //works
}
- (void)refreshRSS:(id)sender {
[mainView addSubview:loadingCover]; //doesn't work
}
EDIT2:
First of all I'm coding with ARC mode and second, loadingCover has been changed to loadingplate, no biggie...
Ok so in my .h file I do this:
UIView *loadingplate;
UIActivityIndicatorView *loadingIndicator;
And in my .m file in viewDidLoad I do this:
CGRect viewRect = CGRectMake(0, 0, 320, 460);
loadingplate = [[UIView alloc] initWithFrame:viewRect];
UIColor *loadingplateColor = [[UIColor alloc] initWithRed:0.0 green:0.0 blue:0.0 alpha:0.8];
[loadingplate setBackgroundColor:loadingplateColor];
loadingplate.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleBottomMargin;
loadingIndicator = [[UIActivityIndicatorView alloc] initWithFrame:viewRect];
[loadingIndicator setContentMode:UIViewContentModeCenter];
[loadingIndicator startAnimating];
loadingIndicator.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleBottomMargin;
[loadingplate addSubview:loadingIndicator];
[mainView addSubview:loadingplate];
EDI3:
After reading Jasarien's answer I tried this in my .h file:
#property (strong, nonatomic) UIView *loadingPlate;
And then in my .m file:
#synthesize loadingPlate = _loadingPlate;
In this file in viewDidLoad I'm creating the view.
But this doesn't seem to work either.

Please see XJones' comment. This answer is probably wrong.
After Edited question:
It seems that since you're using arc, your loadingPlate view is probably being released too soon.
When you alloc and init your loadingPlate view, it'll have a retain count of +1, as expected from an alloc/init. Yet, because you're using ARC, after you add it as a subview of your main view, ARC releases it. Effectively the loadingPlate view is owned by its super view and when you remove it from the superview, the superview releases it, causing the view to be deallocated. Thus when you try to show it again, it's not there anymore and can't be shown.
The solution to this would be to create a property for your loadingPlate view, and give it a 'strong' reference, (effectively the same as declaring the property as a 'retain'). This way, the object that has this property will own the loadingPlate view, keeping a strong reference to it.

You're saying loadingCover.hidden = NO does not work? Have you added the view as a subview to the current showing view?

Try moving the allocation and initialization of that view to the init method. Also, when you call the method to add it again, one thing you can try is to simply check if it exists first probably by:
if (!loadingPlate) {
// allocate and initialize again because somehow it has been released.
}
At least this way you know if the instance of loadingPlate is still being retained.

Your basic logic to create, show, and hide loadingPlate looks fine. I use a very similar implementation abstracted in a UIView subclass in my apps. All of the answers are stabs in the dark b/c the code you posted doesn't show an obvious problem other than the discrepancies in your iVar names. I decided to add this answer in the hope that it helps you find the solution.
You don't need a property. As far as retain semantics go, iVars are strong by default. If you do create a property and synthesize it the way you show than be sure to refer to either self.loadingPlate or _loadingPlate in your code.
Make sure you don't have a typo in your iVar name vs your property name. For example, if you have an iVar called loadingplate but your property is loadingPlate then you will end up with two iVars (loadingplate and loadingPlate) as properties automatically create iVars if they don't match one already defined.
Your logic of creating the loadingPlate view in viewDidLoad and adding/removing it from the superview as needed is totally fine. Just make aure you don't have loadingPlate = nil anywhere other than in viewDidUnload.
If it's possible for the superview frame size to change you should explicitly set loadingPlate.frame = mainView.bounds before adding loadingView as a subview. If the frames don't change this won't matter.
If I think of anything else I'll add it later. Good luck.

Are you sure loadingCover doesn't still have its hidden property set to YES from the previous time displayed?
Try:
- (void)refreshRSS:(id)sender {
loadingCover.hidden = NO;
[mainView addSubview:loadingCover]; //doesn't work
}

Don't you have to use self.loadingplate to call the property strong and make the retain on your view ?

Related

iOS navigationItem.titleView remove margins

I have something like this:
But I need that the view that am setting for the titleView, doesn't has those margins on the left and right side. Something like this:
This is what am actually doing:
#property (nonatomic, strong) XHScrollMenu *scrollMenu; // where XHScrollMenu is a subclass of UIView
- (void)viewdidLoad{
_scrollMenu = [[XHScrollMenu alloc] initWithFrame:self.navigationController.navigationBar.frame];
_scrollMenu.backgroundColor = [UIColor clearColor];
_scrollMenu.delegate = self;
_scrollMenu.selectedIndex = 0;
self.navigationItem.titleView =self.scrollMenu;
}
I tried giving the view a with of 320, but I got the same result. I read in other post, that maybe a subclass make the trick, but don't know how to implement that solution...
How can I make the title view use the entire width?
Try with bounds instead of frame. see different between bounds and frame.
...initWithFrame:self.navigationController.navigationBar.bounds] /// or give frame manually such like CGRectMake(x,y,self.view.frame.size.width, yourHeight);
If this suggestion doesn't help you then sure problem under initWithFrame of XHScrollMenu. Go in this method and check there.

Where and when to initialize/create view programatically

I had this question when/where to create and initialize views that are created programatically, so I hope some discussions here will shed more light on this topic for me.
This slide:
says: "not to initialize something based on the geometry of the view in viewDidLoad" and suggests viewDidAppear.
Imagine my view controller has view. I want to add 10 dynamic UIButtons to it.
Shall I put the code like below to the viewDidAppear?
-(void) viewDidAppear:(BOOL)animated
{
...
UIButton *button1 = [[UIButton alloc] initWithFrame: rect1];
[self.view addSubview: button1];
UIButton *button2 = [[UIButton alloc] initWithFrame: rect2];
[self.view addSubview: button2];
...
}
But this creates the buttons each time the view is shown. Is it what we want?
On the other hand if I put the code in viewDidLoad slide suggest not to initialize geometry of these views there.
Or shall we create buttons in viewDidLoad and set their frames in viewDidAppear?
What approach do you usually take?
But this creates the buttons each time the view is shown. It's true.
So the best thing you can do is to add a boolean (lets name it isLaunched). You set it to FALSE in the method -(void)viewDidLoad
Then add a if condition in your -(void)viewDidAppear where you perform creation of buttons (or other stuff) and set the boolean to true at the end.
You should have something like that :
-(void)viewDidLoad
{
//some settings
isLaunched = FALSE;
}
-(void)viewDidAppear:(BOOL)animated
{
if(!isLaunched)
{
//creating and adding buttons
isLaunched = TRUE;
}
}
zbMax (and now Amar) offered good solutions to implement the view creations in viewDidAppear: I will provide the rational for doing this (over viewDidLoad).
It is pretty simple actually. In viewDidLoad none of the views are actually setup yet, so any attempt to set/create frames or bounds will be extremely inconsistent. Struts and springs (or autolayout) will take effect after this method which will create additional changes to your views. viewDidAppear: is the correct place to do this because you can now rely on existing views and setting frames.
Reason for not playing with the geometry in viewDidLoad is because view is still in the memory and not on the window. Once the view is put on the window, then you can specify geometry. That happens when viewDidAppear is called for your controller.
As recommended, you should do all the initialisation in viewDidLoad as this is one time task and need not be repeated. Hold references to the added subviews and give them appropriate frame in viewDidAppear.
When you are dealing with custom UIView and its subviews, layoutSubviews is the method you need to override in the custom view in order to rearrange the geometry of its subviews.
Hope that helps!

If I don't want to use a nib file, what is the proper implementation of loadView that sizes the root view correctly?

There are a bunch of related questions here, but none that feels like a concise or correct answer. Here's the situation:
I am creating a new ViewController and don't want to use a nib file. My understanding from the Apple docs is that if I don't want to use a nib, I should implement loadView to manually create my own view hierarchy.
However, its not clear to me how I should properly instantiate self.view with the proper bounds (given this view controller might be used in a bunch of different situations, setting it simply to the screen bounds doesn't feel right).
Somehow the default UIViewController loadView does seem to properly initiate the frame size, but its not clear if I'm writing my own version what I should be doing to do this.
There is no need to implement loadView. Instead, implement viewDidLoad and create and add any and all desired subviews you want. Just add them to the default self.view.
If you want to add a view that fills the view controller's view then do something like the following:
- (void)viewDidLoad {
[super viewDidLoad];
UIView *someView = [[UIView alloc] initWithFrame:self.view.bounds];
someView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:someView];
}
In loadView, you should set the view property of viewController, and nothing else. Adding subviews should be done in viewDidLoad.
- (void)loadView {
self.view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 80, 40)];
}
Roopesh Chander has an interesting blog post on which strategy to choose: loadView vs viewDidLoad
for Programmatic UI Setup. He recommends setting the frame in loadView rather than viewDidLoad for maximum efficiency.

Xcode - Image view not hiding

I have an image view in a basic app that I am attempting to set to hidden on load using:
- (void)viewDidLoad
{
my_image.hidden = YES;
}
This code along with some other attribute changes are not functioning at all. I have synthesized the my_image property. Any ideas why this may not be working? Also, please let me know if you need any further information. I'm new to this and it's really bugging me, so thanks in advance!
It's hard to make it clear with a simple code line, my_image.hidden = YES;
But I think you can do the things below :
Print the imageView (your 'my_image' object) in the console to look into it.
Use the other properties of the imageView to see if you can manipulate it, such as changing the frame, setting the background color, or setting an image for it. If you can change the frame, then you may set my_image.hidden = NO; somewhere else.
Create another UIImageView object and add try it!
If none of above works, you can set the frame of 'my_image' to CGRectZero to hide it.
Maybe you forgot to connect the IBOutlet ? Are you using .xib ?
make a breakpoint at line of my_image.hidden = YES; Does it go into the breakpoint ? If it goes into , make sure the my_image is not nil.
UIImageView *imageview = [[UIImageView alloc]init];
[imageview setHidden:YES];
Setter worked for me:
UIImageView * bb = (UIImageView*)[self.view viewWithTag:1];
[bb setHidden:YES];
I had the same problem with hiding the image view but if you remove the #property statement the hidden behaves as it it should.
Set the hidden in viewdidLoad then the IBaction - works fine
.h
IBOutlet UIImageView *crackedimage1;
.m
-(void)viewdidLoad
crackedimage1.hidden = YES;
- (IBAction)crackaction1:(id)sender {
crackedimage1.hidden = NO;};

UIScrollView won't show in UIView

My app is building purely programmatically on UITabBarController above a UINavigationController, which are both declared in my AppDelegate. Inside my navigationcontroller, I'm showing a UIViewController, a custom class. This custom class should show a custom UIView in a UIScrollView and a UIPageControl.
Heres my problem:
self.view seems to create an EXC_BAD_ACCESS error when I call it without declaring self.view = [[UIView alloc] init] (or similar). I was wondering if this was a problem with -(void) loadView but seems like it produces the same error in -(void)viewDidLoad. So I basically had to use self.view = scrollView to even show my scrollView, considering [self.view addSubview:scrollView] produced an error. My UIPageControl should stay on the page all the time, and actually be another part of the view than the UIScrollView. So I tried to add a container-view like this
Code:
container = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0,0,0)];
scrollView.pagingEnabled = YES;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.showsHorizontalScrollIndicator = NO;
// EDIT: ofcourse, I'm also resizing the frame with [scrollView setContentSize:] later, but this is farfetched code to add here.
[container addSubview:scrollView];
self.view = container;
Unfortunately, it seems that I don't get any result at all, and what appears is just an empty view. However, if I add a UILabel or similar, it shows:
[container addSubview:[[UILabel alloc] initWithFrame:CGRectMake(50,50,50,50)]]; // entered above or beneath the addSubview:scrollView line.
My question is: Why doesn't my scrollView appear in the UIView container?
I've noticed that some tutorials say that scrollView must have a delegate, and I agree with the logic - however I can't seem to find out how I set that delegate when I am in my CustomUIViewController-class instead of my AppDelegate.
after you change the UIScrollView size you should use:
[scrollView setNeedsDisplay:YES];
also you implement Delegates the same way you do in other classes:
.h:
#interface MyClass : NSObject <UIScrollViewDelegate>
Okay, the problem seemed to be the initialization - I didn't realize that frame and content was two different things. Seems like the frame that is initializing the view should be whatever size the view should fill, while content is the actual content of whatever should be scrolled. So when I was having problems with user interaction, it was really this.
The problem of why it didn't show in the first place was (stupid.) that the frame was initially, and never changed from, 0,0 so I really lied in my first post.
Thanks to UIScrollView and PageControl: space between views who solved my problem with user interaction.
My steps was to backtrace from self.view:
NSLog(#"%f\n%f",
((UIScrollView*) [[self.view subviews] objectAtIndex:0]).frame.size.width,
((UIScrollView*) [[self.view subviews] objectAtIndex:0]).frame.size.height);
when I realized these were 0 and 0, fixing the problem wasn't too hard :) thanks though, for your efforts Kristian.

Resources