Reputation:
My program "ThreadsNQueues" - see below - fills text lines with "A"s and "B"s concurrently on background threads. When a text line has been filled with 10 characters it will be appended to an output text buffer (it's a NSMutableString) and this buffer should be written out to a UITextView (self.outView
).
Problem: the line self.outView.text=_output;
will never bee executed (tested on simulator iOS 9.2) :-( sorry i'm completely new to multithreading on iOS ...
So my question is: what is wrong with this code and how can i make it better (GCD is required)?
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
NSMutableString *_output;
NSMutableString *_line;
NSLock* _lineLock;
dispatch_queue_t _myQueue;
- (void)viewDidLoad {
[super viewDidLoad];
_output=[NSMutableString string];
_lineLock=[[NSLock alloc] init];
_line=[NSMutableString string];
_myQueue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(dispatch_get_main_queue(), ^{
do {
dispatch_async(_myQueue, ^{
if([_lineLock tryLock]) {
[self append:'A'];
[_lineLock unlock];
}
});
dispatch_async(_myQueue, ^{
if([_lineLock tryLock]) {
[self append:'B'];
[_lineLock unlock];
}
});
} while (true);
});
}
- (void)append:(char)c {
[_line appendFormat:@"%c",c];
if (_line.length==10) {
// line is complete
[_line appendString:@"\n"];
[_output appendString:_line];
NSLog(@"%@",_line);
[_line setString:@""];
dispatch_async(dispatch_get_main_queue(), ^{
// update ui (never called !!!)
self.outView.text=_output;
});
}
}
@end
The Xcode console log looks good:
2016-02-14 09:09:38.607 ThreadsNQueues[2807:62067] BAABAAAAAB
2016-02-14 09:09:38.611 ThreadsNQueues[2807:62067] BBAAAABAAA
2016-02-14 09:09:38.614 ThreadsNQueues[2807:62047] BABBAAABBA
2016-02-14 09:09:38.617 ThreadsNQueues[2807:62044] BBAAABAAAB
2016-02-14 09:09:38.619 ThreadsNQueues[2807:62067] BABBAABBAB
2016-02-14 09:09:38.622 ThreadsNQueues[2807:62047] ABABABABAB
2016-02-14 09:09:38.623 ThreadsNQueues[2807:62047] BBABBBABAA
2016-02-14 09:09:38.624 ThreadsNQueues[2807:62047] BBBBBBABBA
2016-02-14 09:09:38.627 ThreadsNQueues[2807:62047] AABAABAABA
...
Many thanks.
Upvotes: 2
Views: 628
Reputation: 1843
Update your code with the code mentioned below and reason for not updating your UI has already been mentioned in answer above:
You dispatch onto the main thread at the start of your code and then enter an infinite loop, so the main thread runloop will never run again.
Run your threads for appending string in the background and update your UI on the main thread.
- (void)viewDidLoad {
[super viewDidLoad];
_output=[NSMutableString string];
_lineLock=[[NSLock alloc] init];
_line=[NSMutableString string];
_myQueue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
do {
dispatch_async(_myQueue, ^{
if([_lineLock tryLock]) {
[self append:'A'];
[_lineLock unlock];
}
});
dispatch_async(_myQueue, ^{
if([_lineLock tryLock]) {
[self append:'B'];
[_lineLock unlock];
}
});
} while (true);
});
}
Upvotes: 0
Reputation: 119041
You dispatch onto the main thread at the start of your code and then enter an infinite loop, so the main thread runloop will never run again.
If you want to use the same structure you have, dispatch onto your custom queue instead of main and then internally dispatch each async block to one of the provided priority queues.
A better solution could be to use an operation queue and have each operation add a new copy of itself onto the queue when it's done.
Upvotes: 2