I get one problem is that,
This's showads function.
[self.mMainView addSubview:adViewController.view];
//...(my function to display ads)
This's hideads function.
//...(my function to hide ads)
[[AdViewController sharedAdViewController].view removeFromSuperview];
[self.mMainView setNeedsDisplay];
The mMainView is a UIView.
The AdViewController is a UIViewController.
The problems is that after calling showads fucntion, the my ads display on mMainView. But after calling hideads function, the my ads don't disappear, it still appear on mMainView.
Note: After calling hideads and make an interrupt then resume the app, the my ads will disappear.
So, i want to remove it, could you please explain a bit in more detail and show me how to fix it if you can pls ?
You don't need to call setNeedsDisplay when removing or adding subviews. The fact that it updates after an interrupt makes me suspect that you're not calling [[AdViewController sharedAdViewController].view removeFromSuperview]; on the main thread. What is the context of that code?
If it's not on the main thread, you can schedule on it:
dispatch_async(dispatch_get_main_queue(), ^{
[[AdViewController sharedAdViewController].view removeFromSuperview];
});
Related
I have encountered a delay/pause that I was not expecting and the reason so far has me scratching my head. I have a simple game setup where the UIViewController shows a number of UIButtons [PLAY GAME] [VIEW SCORES] etc. which in turn present a different SKScene
My problem is that when I try and set the visibility of these buttons to visible (perviously set to hidden in viewDidLoad) from the UIViewController they take about 5 seconds to actually show.
#implementation ViewController
- (void)presentTitleScene {
// SHOW BUTTONS
[[self logoLabel] setHidden:NO];
[[self gameButton] setHidden:NO];
[[self scoreButton] setHidden:NO];
[[self creditsButton] setHidden:NO];
// PRESENT SCENE
SKScene *titleScene = [TitleScene sceneWithSize:[[self spriteKitView] bounds].size];
[titleScene setName:#"TITLE_SCENE"];
[titleScene setScaleMode:SKSceneScaleModeAspectFill];
[(SKView *)[self view] presentScene:titleScene];
[self setCurrentScene:titleScene];
}
#end
What happens is all the code runs, the SKScene presents correctly, then after about 5-6 seconds the buttons appear? Is there anything I can do about this (force an update) or is it just a case of design it out or live with it?
This happens on both the simulator and the device.
EDIT:
Looking at the output log you can clearly see that after calling preloadTextureAtlases:withCompletionHandler: that execution jumps to another thread. The method preloadTextureAtlases:withCompletionHandler: is called on the main thread and its supposed to preload the textureAtlas(s) on a background thread, but I was under the impression that the completionHandler would call back onto the main thread, is this assumption right or am I wrong?
EDIT_002:
Moved to answer below.
With regards to preloadTextureAtlases:withCompletionHandler: the completionHandler gets called on a background thread, I would assume the same one that was used to preload the atlases. The problem that I was having was that I was using the completion handler to send an NSNotification to my viewController saying "the assets have loaded, start the game" The issue with this is that "Notifications are delivered in the same thread that they are sent from" so my game also started in the background thread. As a consequence the code that set the UIButtons to visible was also running on that same background thread, hence the delay in them reacting to either being made visible or hidden.
The method below is called on a non-main thread, to be specific, in a recording audio queue callback
- (void)myMethod
{
//...
dispatch_async(dispatch_get_main_queue(), ^{
[myGraphView setNeedsDisplayInRect:CGRectMake(a, b, c, d)];
NSLog(#"Block called");
});
//...
}
where myGraphView is a custom UIView object. For what I know, setNeedsDisplayInRect: should be called on main thread which is why I have dispatch_async... in place. Now the problem is the method - (void)drawRect:(CGRect)rect I implemented for myGraph is never called even though the NSLog in the block has been called for many times.
There are a few possibilities here.
From the Class Reference:
Note: If your view is backed by a CAEAGLLayer object, this method has
no effect. It is intended for use only with views that use native
drawing technologies (such as UIKit and Core Graphics) to render their
content.
The other option, which is probably the cause in this case, has to do with the actual geometry. If the provided rectangle is invalid or off screen, the call does nothing. I would suggest you verify the that the rectangle is being calculated as it should be.
Thanks to #Neal's answer which led me to find out that myGraphView was, after it had been alloc-inited the first time, alloc-inited again. However, unlike the first alloc-init after which I added myGraphView to its superview, I forgot to do so after the second alloc-init.
The lesson I've learned here is that when a view is not doing what it's expected to do, such as not being displayed or updated, always check this third possibility where you forget to add it back to its superview after it's got alloc-inited again somewhere in your code. Also, if the view has a delegate you would tend to forget to set it as well.
I have a seemingly simple problem that I cannot for the life of me seem to figure out. In my iOS App, I have a UICollectionView that triggers network operation upon tapping it that can take a few seconds to complete. While the information is being downloaded, I want to display a UIView that fills the cell with a UIActivityIndicatorView that sits in the square until the loading is done, and the segue triggered. The problem is that it never appears. Right now my code looks like:
myLoadView.hidden = NO;
//Network Operation
myLoadView.hidden = YES;
The App simply stops for a couple seconds, and then moves on the the next view. I'd imagine Grand Central Dispatch has somthing to do with the solution, however please keep in mind that this code takes place in prepareForSegue, and the network info needs to be passed to the next View. For this reason not finishing the download before switching scenes has an obvious problem. Any help would be VASTLY appreciated. Thanks!
iOS commits changes in the interfaces after working out a routine. Hence you should perform your network operation in a background thread and then get back back on the main and perform the "show my view now thing". Have a look the below code for reference.
myLoadView.hidden = NO;
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
//Network Operation
dispatch_async(dispatch_get_main_queue(), ^{
myLoadView.hidden = YES;
});
});
Your network operation seems to be carried out on the main thread, aka UI thread. This blocks all further UI calls, including the call to unhide a view, until completion.
To resolve this, make your call asynchronous.
You should read this in full, if you haven't already.
As mentioned by other answers, the problem is that the UIView change doesn't happen until the current method finishes running, which is where you are blocking. Before GCD was available I would split methods in two and use performSelector:withObject:afterDelay (to run the second part also on the UI loop) or performSelectorInBackground:withObject: at the end of the first method. This would commit all the waiting animaations first, then do the actual tasks in the second method.
Well the better option for this type of indication is by using the custom HUD libraries like SVProgressHUD or MBProgressHUD
Most of the time I'm doing projects with storyboard but now I need to mantain an old project that used xib files. My problem is this, I have a ViewController with a scroller \ UIButton \ UITextField on it. If I write something like: [scroller setHidden:YES]; inside ViewDidLoad the scroller will be hidden, but, if I'll put it inside
-(IBAction)checkMember:(id)sender{
[scroller setHidden:YES];
[self checkMemberLog];
Only when those are complete the setHidden will fire up.
How can I force it to fire up instantly? What am I missing?
Try calling checkMemberLog like this:
[self performSelector:#selector(checkMemberLog) withObject:nil afterDelay:0];
Even with a delay of 0, I think this will allow your scroller to be hidden because the selector is queued on the current thread’s run loop, and has to be dequeued before it will run. Even though this happens almost instantly, I'm guessing that an update of the display caused by the setHidden: message is queued first.
If you're more comfortable with storyboard maybe it's worth your time to start a new project and import all your old header/class files. It could save you some time and frustration in the end, depending on how much there is to bring over.
My iOS app has a welcome screen (not to be confused with the default view). The view controller downloads and parses an XML file using NSXMLParser. When it completes it's task it makes a button visible, which when clicked calls "presentViewController" which takes the user into the actual app. This worked fine.
I then decided that I would just like the the app to automatically transition, and so I removed the button altogether and moved the call to presentViewController into the "parserDidEndDocument" delegate method. The method gets called but nothing happens. I suspect it has something to do with the context, but when I log "self" it prints an instance of the welcome view controller. What am I doing wrong? How should I fix this?
Try dispatching it to the main thread. Async objects like NSXmlParser work on separate threads, but UIKit updates must be done on the main thread.
dispatch_async(dispatch_get_main_queue(), ^{
[self presentViewController]; //Or whatever
});