Painting a UIView from a background NSThread? - iphone

I am developing GL paint application.
To paint any object, I am using UIView that implemented.
Starting paint method :
- (void)viewDidLoad {
....
[NSThread detachNewThreadSelector:#selector(paintingObjects)
toTarget:self
withObject:nil];
}
- (void)paintingObjects {
while(1) {
[NSThread sleepForTimeInterval:2];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
ImplementedView *tmp = [self view];
[tmp draw];
[pool drain];
}
}
But it is not working (doesn't paint object).
What is wrong here ?
Please help me guys.
Thanks in advance.

All user-interface classes are not thread-safe and must be called from the main thread:
- (void)paintingObjects {
while(1) {
[NSThread sleepForTimeInterval:2];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
ImplementedView *tmp = [self view];
[tmp performSelectorOnMainThread:#selector(draw) withObject:nil waitUntilDone:YES];
[pool drain];
}
}
In this case, you would likely be better off using NSTimer.

Related

Can we thread the web-service and insert in in custom table cell?

The thing is i have to make Custom cell of UITable, i have to call large webservice with many data which will take longer tym to load it once. So i want to apply threading in it. now my que is. can we at run -time insert value one by one in custom cell , as user will see data comming one by one at run time..?? if yes how we can do that.
yes you can ... try this
- (void)viewDidLoad
{
myApp = (myAppDelegate *) [[UIApplication sharedApplication] delegate];
[self performSelectorInBackground:#selector(startParsing) withObject:nil];
[super viewDidLoad];
}
- (void) startParsing
{
[self performSelectorOnMainThread:#selector(startIndicator) withObject:nil waitUntilDone:NO];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *url = [[NSURL alloc] initWithString:#"http://abc.com"];
NSData *data = [NSData dataWithContentsOfURL:url];
// 2 -- parsing
parser = [[VolMyParser alloc] init];
[parser parseXML:data];
[data release];
//[parser print];
[self performSelectorOnMainThread:#selector(updateTable) withObject:nil waitUntilDone:NO];
[pool release];
}
- (void) startIndicator
{
av.hidesWhenStopped = YES;
[av startAnimating];
}
- (void) updateTable
{
[av stopAnimating];
[myTable reloadData];
}
Hope its gives you an Idea...

How to hold for a moment in program?

I am fetching data from facebook and during the time of fetching the data, it is taking few milliseconds or a second. I want to be on hold untill fetched data perfectly.
How to write code for this?
- (void)viewDidLoad
{
[self performSelectorInBackground:#selector(startFatching) withObject:nil];
[super viewDidLoad];
}
- (void) startFatching
{
[self performSelectorOnMainThread:#selector(startIndicator) withObject:nil waitUntilDone:NO];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// your code
[self performSelectorOnMainThread:#selector(stopIndicator) withObject:nil waitUntilDone:NO];
[pool release];
}
- (void) startIndicator
{
av.hidesWhenStopped = YES;
[av startAnimating];
}
- (void) stoprIndicator
{
[av stopAnimating];
}
hope this will give you some idea

Asynchronous Loading of Image - Crashing If Dealloced

I have a UIViewController presented by a navigation controller. This UIViewController loads an image asynchronously as follows :
[self performSelectorInBackground:#selector(downloadData) withObject:nil];
- (void)downloadData {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
LocationDetails * details = [[LondonDatabase database] locationDetails : UniqueID];
NSData * imageData = [NSData dataWithContentsOfURL : [NSURL URLWithString : [details image]]];
picture = [[UIImage alloc ]initWithData:imageData];
[self performSelectorOnMainThread : #selector(updateUI) withObject : nil waitUntilDone : NO];
[pool release];
}
The problem is that if this view controller is popped off the stack while the above method is executing the app crashes with the error :
bool _WebTryThreadLock(bool), 0x61b3950: Tried to obtain the web lock
from a thread other than the main thread or the web thread. This may
be a result of calling to UIKit from a secondary thread. Crashing
now...
Can anyone help ?
Thanks,
Martin
Use an NSThread and keep a handle to that in the view controller object. When the view controller dealloc's, cancel the thread (assuming it has not completed). In downloadData, check that the thread isn't cancelled before trying to access elements of the view controller. That is to say, if the thread has been cancelled, just return. I had a similar issue and this is how I solved it.
Here's the code (which was loading an image into a custom table cell):
-(void)displayImage:(id)context
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIImage *image = (UIImage *)context;
[spinner stopAnimating];
brandImage.image = image;
[brandImage setNeedsDisplay];
[pool release];
}
-(void)fetchImage:(id)context
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *url = (NSString *)context;
if ([[NSThread currentThread] isCancelled])
return;
UIImage *image = [ArtCache imageForURL:url];
if (![[NSThread currentThread] isCancelled]) {
[self performSelectorOnMainThread:#selector(displayImage:) withObject:image waitUntilDone:NO];
}
[pool release];
}
-(void)showBrandImageURL:(NSString *)url
{
[spinner startAnimating];
brandImage.image = nil;
if (imageLoadThread) {
[imageLoadThread cancel];
[imageLoadThread release];
}
imageLoadThread = [[NSThread alloc] initWithTarget:self selector:#selector(fetchImage:) object:url];
[imageLoadThread setThreadPriority:0.8];
[imageLoadThread start];
}
These were 3 methods in the custom table cell class. The last one was the one called from cellForRowAtIndexPath:. The other two support the one that is called.

RSS on a different thread doesnt work but works fine when on the main thread

I'm trying to get an rss parser on a different thread in my iphone app, but when I do this I only get the spinning indicator (i.e., nothing). But if I comment out the call [NSThread....] in viewDidAppear, and uncomment the line [self loadData], everything works (but then its not on a different thread). Am I missing something? Thanks for any insight you can provide here!!
Here is the code.
- (void)viewDidAppear:(BOOL)animated {
[NSThread detachNewThreadSelector:#selector(loadData) toTarget:self withObject:nil];
//[self loadData];
[super viewDidAppear:animated];
}
- (void)loadData {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (items == nil) {
[activityIndicator startAnimating];
Parser *rssParser = [[Parser alloc] init];
[rssParser parseRssFeed:#"http://www.mywebsite.com/xml" withDelegate:self];
[rssParser release];
} else {
[self.tableView reloadData];
}
[pool release];
}
All UI changes should be made on the main thread:
- (void)viewDidAppear:(BOOL)animated {
if (items == nil)
{
[activityIndicator startAnimating];
[NSThread detachNewThreadSelector:#selector(loadData) toTarget:self withObject:nil];
}
else
{
[self.tableView reloadData];
}
[super viewDidAppear:animated];
}
- (void)loadData {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Parser *rssParser = [[Parser alloc] init];
[rssParser parseRssFeed:#"http://www.mywebsite.com/xml" withDelegate:self];
[rssParser release];
[pool release];
}
Check if items is null, if it is, start animating the indicator and then start the new thread.

Image view not updating on NSThread

I'm trying to make a test app which measures the performance for threads. However, I'm trying to set an image to imageview on a thread and it's not updating. In fact, the methods setImage1 and setImage2 aren't even getting called. Any ideas?
Look at the code for details
#import "UntitledAppDelegate.h"
#import <QuartzCore/QuartzCore.h>
#implementation UntitledAppDelegate
#synthesize window, imageView1, imageView2, label1, label2, label0;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[window makeKeyAndVisible];
return YES;
}
-(IBAction) startSeparate:(id) sender
{
imageView1.image = imageView2.image = nil;
double prev;
start = prev = CACurrentMediaTime();
[self setImage1];
label1.text = [NSString stringWithFormat:#"%.10g", CACurrentMediaTime() - prev];
prev = CACurrentMediaTime();
[self setImage2];
label2.text = [NSString stringWithFormat:#"%.10g", CACurrentMediaTime() - prev];
}
-(IBAction) startThreaded:(id) sender
{
imageView1.image = imageView2.image = nil;
double prev;
NSThread *t1 = [[NSThread alloc] init];
[t1 start];
NSThread *t2 = [[NSThread alloc] init];
[t2 start];
start = prev = CACurrentMediaTime();
//This doesn't work
//[self performSelector:#selector(setImage1) onThread:t1 withObject:nil waitUntilDone:NO];
//But this does
[self performSelectorInBackground:#selector(setImage1) withObject:nil];
label1.text = [NSString stringWithFormat:#"%.10g", CACurrentMediaTime() - prev];
prev = CACurrentMediaTime();
//This doesn't work
//[self performSelector:#selector(setImage2) onThread:t2 withObject:nil waitUntilDone:NO];
//But this does
[self performSelectorInBackground:#selector(setImage2) withObject:nil];
label2.text = [NSString stringWithFormat:#"%.10g", CACurrentMediaTime() - prev];
}
-(void) setImage1
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIImage *image1 = [UIImage imageNamed:#"bird.png"];
imageView1.image = image1;
[self pictureDone];
[pool drain];
}
-(void) setImage2
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIImage *image2 = [UIImage imageNamed:#"bird.png"];
imageView2.image = image2;
[self pictureDone];
[pool drain];
}
-(void) pictureDone
{
done++;
NSLog(#"%i", done);
if (done == 2) {
label0.text = [NSString stringWithFormat:#"%.10g", CACurrentMediaTime() - start];
done = 0;
}
}
#end
Never change anything in a currently displayed UIView from a background thread. There are a million different synchronization problems that you can encounter. Download the image in the background thread, and then call another method on the main thread (from the background thread) to actually update the UIImageView
performSelectorOnMainThread:...
As for the problem with the method not running, try this instead:
[self performSelectorInBackground:#selector(setImage2:) withObject:nil];
(adding a colon after setImage2).
Also, I don't think those two NSThread objects (t1 and t2) are necessary, and they are also probably creating a memory leak.
Technically, NSThread itself do not create run loop automatically, then the performSelector:onThread won't work if you just create thread that way.