hello i created a nsnotificationcenter in appdelegate.when the download is finished it sends a notification. i have a activity indicator on my class and i what to hide it when the download is finished but it doesn't work. i can see my nslog but it doesn't hide the acitivyindicator.
here is my code:
viewdidload:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(refreshView:) name:#"loadingFinished" object:nil];
my function:
-(void)refreshView:(NSNotification*)notification
{
activity.hidden = YES;
self.view.userInteractionEnabled =YES;
NSLog(#"alles geladen zeiger wird geladen");
}
if you are at any other thread, then it will not work cz UI not work in inner thread. use this
-(void)refreshView:(NSNotification*)notification
{
dispatch_async(dispatch_get_main_queue(), ^{
activity.hidden = YES;
self.view.userInteractionEnabled =YES;
});
NSLog(#"alles geladen zeiger wird geladen");
}
A notification callback may not be called on the main thread, but all your UI updates must be done in the main thread. So on your notification callback, use [self performSelectorOnMainThread:#selector(refreshViewFromMainThread)], and declare a new method:
- (void)refreshViewFromMainThread
{
activity.hidden = YES;
self.view.userInteractionEnabled = YES;
}
Related
I add breakpoint and find that it block in the method that
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
// init local data
[[PDKeychainBindings sharedKeychainBindings] setObject:#"0" forKey:kNEED_GESTURE_LOGIN];
// register notification to notice switching RootVC
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(switchRootControllerWithType:)
name:kNoti_SwitchRootView
object:nil];
// init the third part SDK
[self setupShareSDK];
[self setupBugly];
[self setupUMeng];
[self setupIQKeyBoard];
[self setupZhugeIOWithOptions:launchOptions];
[self setupTrusfort];
// register push service
[self setupJPushWithOptions:launchOptions];
[self dealWithRemoteNotification:launchOptions];
// set local flag
[KXUserIntroManager setupFlag];
if (self.remoteNotification) {
if ([AccountStateManager isLogin])
[self.loginNavigationController showGesturePDViewController];
self.window.rootViewController = self.loginNavigationController;
} else {
self.window.rootViewController = self.launchController;
}
return YES;
}
i also try the way in stackOverFlow ,Add the following code to the above method
NSArray *args = [NSProcessInfo processInfo].arguments;
for(NSString *arg in args){
if ([arg isEqualToString:#"NoAnimations"]) {
[UIView setAnimationsEnabled:false];
}
}
Image link
it is the detail of didFinishLaunching method. it just init some data and create a notification
While this is not a direct answer to your question, it may well be that your issue is symptomatic of the very evident fact that you are doing much too much work, on the main thread, in didFinishLaunchingWithOptions. Your main job in this method is to get out of the way and let the runtime launch the app. You are doing the exact opposite of that.
Brief : I have a queue that sends notifications. A view controller subscribes to them and when it receives them it displays an image.
Problem : the first time, everything goes well. When I come back later to the view, I see the log that the notification was received but the image is not displayed.
Note : the background thread is a queue : dispatch_queue_create("scan", DISPATCH_QUEUE_SCAN) and from this queue the notification are posted.
#property(strong, nonatomic) id observer;
- (void)viewDidAppear:(BOOL) animated {
[super viewDidAppear:animated];
self.observer = [[NSNotificationCenter defaultCenter] addObserverForName:MY_NOTIF object:nil queue:nil usingBlock:^(NSNotification *note) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"notification");
[self.img setImage:[UIImage imageNamed:#"register-ok"]];
[self.img setNeedsDisplay]; // useless
});
}
}
- (void)viewDidDisappear:(BOOL) animated {
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:observer name:MY_NOTIF object:nil];
}
This is really getting me crazy. Thanks in advance for your help
EDIT : changes done :
NSLog(#"viewDidAppear. createObserver. self: %#");
[[NSNotificationCenter defaultCenter] addObserverForName:MY_NOTIF object:nil queue:nil usingBlock:^(NSNotification *note) {
NSLog(#"will call redraww. self: %#");
[self performSelectorOnMainThread:#selector(redraww:) withObject:nil waitUntilDone:YES];
}
-(void) redraww:(NSObject*)input {
NSLog(#"redraww self : %#", self);
[self.img setImage:[UIImage imageNamed:#"register-ok"]];
}
-(void) onRegistrationFinish {
NSLog(#"remove observer. self %#", self);
[[NSNotificationCenter defaultCenter] removeObserver:self name:(NSString *)NOTIF_SOLE_UUID object:nil];
}
console log
viewDidAppear. createObserver self: <RegisterLeftViewController: 0x15e34550>
will call redraww. self:<RegisterLeftViewController: 0x15e34550>
redrawww self : <RegisterLeftViewController: 0x15e34550>
remove observer. self <RegisterLeftViewController: 0x15e34550>
************************* Second time
viewDidAppear. createObserver self: <RegisterLeftViewController: 0x15e98ba0>
will call redraww. self:<RegisterLeftViewController: 0x15e34550>
redrawww self : <RegisterLeftViewController: 0x15e34550>
remove observer. self <RegisterLeftViewController: 0x15e98ba0>
Seems like you're doing a few things that could cause trouble.
The trouble could be coming from a number of places. Here's some things that may fix the problem:
Move observer registration to viewDidLoad
Move observer de-registration to dealloc
use __block __weak id observer to ensure self is properly captured in your notification handler. See iOS NSNotificationCenter Observer not being removed
Hope that helps
I have a UIViewController with button that brings another UIViewController. with clicking on button , as shown in my NSLog, and when this is done, I want to send a notification to load another viewcontroller . Well, although it seems everything is done right, somehow it does not work and the UIViewController not appear. Here is the code:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(infoPage:)
name:#"InfoPage" object:nil ];
-(void) infoPage:(NSNotification*)notification
{
NSLog(#"Code executing in Thread %#",[NSThread currentThread] );
InfoCtrol *i = [[InfoCtrol alloc] init];
i.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:i animated:YES];
}
my tabbaritem button
-(void)info {
[[NSNotificationCenter defaultCenter] postNotificationName:#"InfoPage"
object:nil
userInfo:nil];
NSLog(#"test not");
}
I think my problem is that: It's not in a mainThread but I do n't know how should I solved that:
I also used this but it didn't bring the UIViewController:
[self performSelectorOnMainThread:#selector(test) withObject:nil waitUntilDone:NO];
-(void)test{
[[NSNotificationCenter defaultCenter] postNotificationName:#"InfoPage"
object:nil
userInfo:nil];
}
If I just put this code in button, it displays the UIViewController, but I want to use NSNotificationCenter
InfoCtrol *i = [[InfoCtrol alloc] init];
i.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:i animated:YES];
My Log:
Code executing in Thread <NSThread: 0x1fd7c7e0>{name = (null), num = 1}
Update:
How should i remove last thread from mainThread
I don't know why you want to use a notification here, when you can perform the action directly without issue. But a simple thing you can do in notification methods that need to update UI is to just have them call themselves on the main thread if they're not already running on that thread:
-(void)myNotificationMethod:(NSNotification*)note {
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:#selector(myNotificationMethod:)
withObject:note
waitUntilDone:NO];
return;
}
// ... do some UI stuff
InfoCtrol *i = [[InfoCtrol alloc] init];
[self.navigationController pushViewController:i animated:YES];
}
I have 3 screens on my app.First is login. Second is search and third is process the task.
On login i retrieve data from a web service. It returns data in XML format. So the data is considerably large. So i am doing that task on a background thread like this to stop Mainthread freezing up on me:
-(BOOL)loginEmp
{
.....some computation
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) {
[self getAllCustomerValues];
});
}
-(void)getAllCustomerValues
{
....more computation.Bring the data,parse it and save it to CoreData DB.
//notification - EDIT
NSNotification *notification =[NSNotification notificationWithName:#"reloadRequest"
object:self];
[[NSNotificationCenter defaultCenter] postNotification : notification];
}
//EDIT
//SearchScreenVC.m
- (void)viewDidLoad
{
....some computation
[self.customerActIndicator startAnimating];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(stopActivityIndicator)
name:#"reloadRequest"
object:nil];
}
- (void)stopActivityIndicator
{
[self.customerActIndicator stopAnimating];
self.customerActIndicator.hidesWhenStopped = YES;
self.customerActIndicator.hidden =YES;
NSLog(#"HIt this at 127");
}
So on condition that login was successful, i move to screen 2. But the background thread is still in process( i know because i have logs logging values) . I want an activity indicator showing up here (2nd screen)telling user to wait before he starts searching. So how do i do it?How can i make my activity indicator listen/wait for background thread. Please let me know if you need more info.Thanks
EDIT: so I edited accordingly but the notification never gets called. I put a notification at the end of getAllCustomerValues and in viewDidLoad of SearchScreen i used it. That notification on 2nd screen to stop animating never gets called. What is the mistake i am doing.?Thanks
EDIT 2: So it finally hits the method. I dont know what made it to hit that method. I put a break point. I wrote to stop animating but it wouldn't. I wrote hidesWhenStoppped and hidden both to YES. But it still keeps animating.How do i get it to stop?
Ok, if it is not the main thread, put the following in and that should fix it.
- (void)stopActivityIndicator
{
if(![NSThread isMainThread]){
[self performSelectorOnMainThread:#selector(stopActivityIndicator) withObject:nil waitUntilDone:NO];
return;
}
[self.customerActIndicator stopAnimating];
self.customerActIndicator.hidesWhenStopped = YES;
self.customerActIndicator.hidden =YES;
NSLog(#"HIt this at 127");
}
Could you put your background operation into a separate class and then set a delegate on it so you can alert the delegate once the operation has completed?
I havent tried this, its just an idea :)
You could use a delegate pointing to your view controller & a method in your view controller like:
- (void) updateProgress:(NSNumber*)percentageComplete {
}
And then in the background thread:
float percentComplete = 0.5; // for example
NSNumber *percentComplete = [NSNumber numberWithFloat:percentComplete];
[delegate performSelectorOnMainThread:#selector(updateProgress:) withObject:percentageComplete waitUntilDone:NO];
In my secondView I do this:
-(void)viewDidDisappear:(BOOL)animated
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dbq = [[dbqueries alloc] init];
[[NSNotificationCenter defaultCenter] postNotificationName:#"abc" object:nil];
//disabling a button and turning a progressView in the mainView on
dispatch_async(queue, ^{
//WORK
});
}
The notification disables a button and causes a progressView(in the progressView there is an ActivityIndicator) on the mainView to start.
In the area, where work is done, a method is called 3 to 6 times and if they are all done, I send another notification to the mainView to enable the button and to stop the progressView.
Now the weird thing is, that the button gets enabled at the right time but the progressView stops randomly after a few seconds
- (void)enableStartButton
{
NSLog(#"enableStartButton");
self.startARButton.enabled = YES;
[self.progressView setHidden:YES];
[[self.progressView.subviews objectAtIndex:0] stopAnimating];
}
I really don't know whats going on here, thanks in advance!