My basic problem is that I cannot seem to work out how to bring the Activity indicator to the top so I can show that a process is running while new data is populating the UITableView. To load new data I am using a Segmented Control. When segment 0 is pressed it will load the first xml feed and when segment 1 is pressed it will load a second xml feed. I have tried using dispatch_queue_t etc. it does load the information and repopulate the table, it just doesn't show the indicator.
This is the code i am currently using.
if (Seg.selectedSegmentIndex == 0) {
timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:#selector(loading) userInfo:nil repeats:YES];
dispatch_queue_t loader = dispatch_queue_create("a", NULL);
dispatch_async(loader, ^{
xml = [[XmlParser alloc]init];
url = [NSURL URLWithString:kTodaysReport];
dict = [[NSMutableDictionary alloc]init];
[xml loadXML:url];
[tableView addSubview:ActInd];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(handleUpdate:) name:#"update" object:nil];
});
});
}
else if (Seg.selectedSegmentIndex ==1){
// tableView = [[UITableView alloc]init];
timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:#selector(loading) userInfo:nil repeats:YES];
dispatch_queue_t loader = dispatch_queue_create("a", NULL);
dispatch_async(loader, ^{
xml = [[XmlParser alloc]init];
url = [NSURL URLWithString:kMonthsReport];
dict = [[NSMutableDictionary alloc]init];
[xml loadXML:url];
[tableView addSubview:ActInd];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(handleUpdate:) name:#"update" object:nil];
});
});
}
Thanks in advance.
EDIT:Relevant code
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_queue_t loader = dispatch_queue_create("a", NULL);
timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:#selector(loading) userInfo:nil repeats:YES];
dispatch_async(loader, ^{
xml = [[XmlParser alloc]init];
url = [NSURL URLWithString:kTodaysReport];
dict = [[NSMutableDictionary alloc]init];
[xml loadXML:url];
[UiTableView addSubview:ActInd];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(handleUpdate:) name:#"update" object:nil];
[ActInd stopAnimating];
[UiTableView reloadData];
});
});
}
-(void)handleUpdate:(NSNotification*)notification{
mainArray = [xml parsedArray];
[UiTableView reloadData];
}
-(void)loading{
if (![xml val]) {
[ActInd startAnimating];
}else
{
[ActInd stopAnimating];
[UiTableView reloadData];
}
}
-(IBAction)segvalueChange:(id)sender{
if (Seg.selectedSegmentIndex == 0) {
timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:#selector(loading) userInfo:nil repeats:YES];
dispatch_queue_t loader = dispatch_queue_create("a", NULL);
dispatch_async(loader, ^{
xml = [[XmlParser alloc]init];
url = [NSURL URLWithString:kTodaysReport];
dict = [[NSMutableDictionary alloc]init];
[xml loadXML:url];
[UiTableView addSubview:ActInd];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(handleUpdate:) name:#"update" object:nil];
});
});
}
else if (Seg.selectedSegmentIndex ==1){
// UiTableView = [[UITableView alloc]init];
timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:#selector(loading) userInfo:nil repeats:YES];
dispatch_queue_t loader = dispatch_queue_create("a", NULL);
dispatch_async(loader, ^{
xml = [[XmlParser alloc]init];
url = [NSURL URLWithString:kMonthsReport];
dict = [[NSMutableDictionary alloc]init];
[xml loadXML:url];
[UiTableView addSubview:ActInd];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(handleUpdate:) name:#"update" object:nil];
});
});
}
else{
}
}
The problem is that you are interacting with the UI on a background thread. Move all UI related code (including that which interacts with the activity view) into the GCD block for the main thread.
Related
This problem, when i swipe screen API Calls are to be made, separate calls for separate swipe i.e. Left, Right, Top, Bottom. Also there has to be Stop API which has to be sent in 1 minute delay of swipe.
Example Camera moving on swipe for 1 second and stops:
Swipe Left -> Left() GET API is called with AFNetworking -> (So Camera starts moving to left) -> Soon after Left API is triggered -> 1 second delay -> Stop GET API is called with AFNetworking. Repeats same method for Right(), Top(), Bottom()
I am not able to achieve this smoothly, I use this logic.
- (void)didSwipe:(UISwipeGestureRecognizer*)swipe{
if (swipe.direction == UISwipeGestureRecognizerDirectionLeft) {
[self performSelector:#selector(moveRight) withObject:self afterDelay:0.0];
[self performSelector:#selector(stop:) withObject:self afterDelay:1.0];
} else if (swipe.direction == UISwipeGestureRecognizerDirectionRight) {
[self performSelector:#selector(moveLeft) withObject:self afterDelay:0.0];
[self performSelector:#selector(stop:) withObject:self afterDelay:1.0];
} else if (swipe.direction == UISwipeGestureRecognizerDirectionUp) {
[self performSelector:#selector(moveDown) withObject:self afterDelay:0.0];
[self performSelector:#selector(stop:) withObject:self afterDelay:1.0];
} else if (swipe.direction == UISwipeGestureRecognizerDirectionDown) {
[self performSelector:#selector(moveUp) withObject:self afterDelay:0.0];
[self performSelector:#selector(stop:) withObject:self afterDelay:1.0];
}
}
This are Method calls
-(void) moveRight
{
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setValue:#"MoveRight" forKey:#"direction"];
[self changeDirection:parameters];
}
-(void) moveLeft
{
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setValue:#"MoveLeft" forKey:#"direction"];
[self changeDirection:parameters];
}
-(void) moveUp
{
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setValue:#"MoveUp" forKey:#"direction"];
[self changeDirection:parameters];
}
-(void) moveDown
{
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setValue:#"MoveDown" forKey:#"direction"];
[self changeDirection:parameters];
}
-(void) stop
{
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setValue:#"Stop" forKey:#"direction"];
[self changeDirection:parameters];
}
Now ChangeDirection Method
-(void) changeDirection:(NSDictionary *) parameters
{
dispatch_queue_t myQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(myQueue, ^{
[RestHandler afnetworkingGetApiCall():parameters :^(id response, NSString *respMsg)
{
}];
dispatch_async(dispatch_get_main_queue(), ^{
});
});
}
Hope I am able to explain my question. Let me know if its not clear
Cheers.
i think, you have to create model for each response. then for each call you have to create common operation queue.
sharing a post using FBSDK in iOS . i Got shared even when clicking cancel button it always calling didCompleteWithResults delegate method.
- (void) sharer: (id<FBSDKSharing>)sharer didCompleteWithResults: (NSDictionary *)results
{
NSLog(#"results count %lu %#",(unsigned long)results.count,results);
if(results)
{
NSMutableDictionary *cb = [[NSMutableDictionary alloc] init];
[cb setObject:#"0" forKey:#"alertid"];
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(showAlert:) userInfo:cb repeats:NO];
[cb release];
}
else
{
NSMutableDictionary *cb = [[NSMutableDictionary alloc] init];
[cb setObject:#"2" forKey:#"alertid"];
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(showAlert:) userInfo:cb repeats:NO];
[cb release];
}
}
- (void) sharerDidCancel:(id<FBSDKSharing>)sharer
{
NSMutableDictionary *cb = [[NSMutableDictionary alloc] init];
[cb setObject:#"2" forKey:#"alertid"];
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(showAlert:) userInfo:cb repeats:NO];
[cb release];
}
I am using AVPlayer to play music via Streaming URLs. Upon playing the first song the CPU is at about 3-4%, but each time a new song gets played the CPU will jump up and seem to get stacked on itself. Why is this happening? This is the code I am using to play music.
- (void)updateTime {
UIImage *pauseButtonImage = [UIImage imageNamed:#"Pause"];
float duration = CMTimeGetSeconds(self.player.currentItem.duration);
float current = CMTimeGetSeconds(self.player.currentTime);
self.durationProgressView.progress = (current/duration);
if (self.durationProgressView.progress == 0)
{
[self.playPauseButton setBackgroundImage:pauseButtonImage forState:UIControlStateNormal];
}
}
-(void)playCurrentArtist:(NSDictionary *)currentArtist
{
NSString *streamString = [currentArtist objectForKey:#"stream_url"];
NSString *urlString = [NSString stringWithFormat:#"%#?client_id=%#", streamString,CLIENT_ID];
NSURL *URLFromString = [NSURL URLWithString:urlString];
self.player = nil;
AVPlayer *playerWithURL = [[AVPlayer alloc]initWithURL:URLFromString];
self.player = playerWithURL;
[self.player play];
self.durationProgressView.hidden = NO;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:[self.player currentItem]];
self.timer = [NSTimer scheduledTimerWithTimeInterval:.05 target:self selector:#selector(updateTime) userInfo:nil repeats:YES];
}
-(void)itemDidFinishPlaying:(NSNotification *) notification {
//if there are no tracks in queue
if (![self.hostQueue count]) {
NSLog(#"nothing in queue upon song finishing");
[[NSNotificationCenter defaultCenter]removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:[self.player currentItem]];
[self.hostCurrentArtist removeAllObjects];
[self setCurrentArtistFromCurrentArtist:self.hostCurrentArtist];
NSArray *argsCurrentArray = #[self.hostCurrentArtist];
[self.socket emit:kCurrentArtistChange args:argsCurrentArray];
}
else {
[self playNextSongInQueue];
[self setCurrentArtistFromCurrentArtist:self.hostCurrentArtist];
};
}
-(void)playNextSongInQueue
{
if ([self.hostQueue count]) {
[self.audioPlayer stop];
[self.timer invalidate];
[[NSNotificationCenter defaultCenter]removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:[self.player currentItem]];
UIImage *pausedButtonImage = [UIImage imageNamed:#"Pause"];
//Rearange tracks and current songs and emit them to the sever.
NSDictionary *currentTrack = [self.hostQueue objectAtIndex:0];
self.hostCurrentArtist = [currentTrack mutableCopy];
[self.hostQueue removeObjectAtIndex:0];
[self.tableView reloadData];
[self playCurrentArtist:self.hostCurrentArtist];
[self.playPauseButton setBackgroundImage:pausedButtonImage forState:UIControlStateNormal];
self.audioPlayer.delegate = self;
self.durationProgressView.hidden = NO;
self.timer = [NSTimer scheduledTimerWithTimeInterval:.5 target:self selector:#selector(updateTime) userInfo:nil repeats:YES];
NSArray *argsWithQueue = #[self.hostQueue];
NSArray *arrayWithTrack = #[currentTrack];
[self setCurrentArtistFromCurrentArtist:self.hostCurrentArtist];
}
}
I have used below code for do a synchronization with web server. It is working but UI freeze for a moment becasue getUnsyncTicketsFromServer method calling in main queue. I tried to do it in separate queue. Then it doesn't call delegate methods(requestReturnedData).
[NSTimer scheduledTimerWithTimeInterval:320.0 target:self selector:#selector(syncTickets) userInfo:nil repeats:YES];
-(void)syncTickets{
[self sendUnsyncedTickets];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 6 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 6 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self getUnsyncTicketsFromServer];
});
});
}
-(void)requestReturnedData:(NSData *)data{
}
edit --
-(void)getUnsyncTicketsFromServer{
ServiceConnector *serviceConnector = [[ServiceConnector alloc] init];
serviceConnector.delegate = self;
[serviceConnector getTicketsFromServer];
dataMethod = #"get";
}
#implementation YourClass () {
ServiceConnector *_serviceConnector;
}
...
-(void)getUnsyncTicketsFromServer {
_serviceConnector = [[ServiceConnector alloc] init];
_serviceConnector.delegate = self;
[_serviceConnector getTicketsFromServer];
dataMethod = #"get";
}
If you are using arc, I think your serviceConnector must be getting released, so store the object as an instance variable.
After trying many ways to call a function in new thread only the below code worked for me
[NSThread detacNewThreadSelector:#selector(temp:) toTarget:self withObject:self];
The below didn't work:
NSThread *updateThread1 = [[NSThread alloc] initWithTarget:self selector:#selector(temp:) object:self];
NSThread *updateThread1 = [[NSThread alloc] init];
[self performSelector:#selector(temp:) onThread:updateThread1 withObject:self waitUntilDone:YES];
Now when i try to call NSTimer or perform selector in timer: function it does not works Find below the code
int timeOutflag1 = 0;
-(void)connectCheckTimeOut
{
NSLog(#"timeout");
timeOutflag1 = 1;
}
-(void)temp:(id)selfptr
{
//[selfptr connectCheckTimeOut];
NSLog(#"temp");
//[NSTimer scheduledTimerWithTimeInterval:5 target:selfptr selector:#selector(connectCheckTimeOut) userInfo:nil repeats:NO];
[selfptr performSelector:#selector(connectCheckTimeOut) withObject:nil afterDelay:5];
}
- (IBAction)onUart:(id)sender {
protocolDemo1 *prtDemo = [[protocolDemo1 alloc] init];
//NSThread *updateThread1 = [[NSThread alloc] initWithTarget:self selector:#selector(temp:) object:self];
//[self performSelector:#selector(temp:) onThread:updateThread1 withObject:self waitUntilDone:YES];
// [updateThread1 start];
[self performSelector:#selector(temp:) withObject:self afterDelay:0];
while(1)
{
NSLog(#"Whieloop");
if(timeOutflag1)
{
timeOutflag1 = 0;
break;
}
if([prtDemo isConnected])
break;
}
}
If i use [self performSelector:#selector(connectCheckTimeOut) withObject:nil afterDelay:5];
in onUart function then it works properly i can see Timeout printf but inside temp it does not work.
NSTimer is run-loop based, so if you want to use one on a background thread that you're spawning and managing yourself, you will need to start a runloop on that thread. Read up on NSRunLoop. The short version might look something like:
- (void)timedMethod
{
NSLog(#"Timer fired!");
}
- (void)threadMain
{
NSRunLoop* rl = [NSRunLoop currentRunLoop];
NSTimer* t = [NSTimer scheduledTimerWithTimeInterval: 1.0 target: self selector: #selector(timedMethod) userInfo:nil repeats:YES];
[rl run];
}
- (void)spawnThread
{
[NSThread detachNewThreadSelector: #selector(threadMain) toTarget:self withObject:nil];
}