I'm new to IOS I need to implement NSThread in my program, but when it invoked it shows an SIGABRT error. my current code is given below
XMLParser.m
-(void)loadXML
{
categories =[[NSMutableArray alloc]init];
NSString *filepath =[[NSBundle mainBundle]pathForResource:#"cd_catalog" ofType:#"xml"];
NSData *data =[NSData dataWithContentsOfFile:filepath];
parser=[[NSXMLParser alloc]initWithData:data];
parser.delegate =self;
[parser parse];
}
ViewController.m
- (void)viewDidLoad
{
xmlParser =[[XMLParser alloc]init];
NSThread *myThread =[[NSThread alloc]initWithTarget:self selector:#selector(loadXML) object:nil];
[myThread start];
[super viewDidLoad];
}
please tell me what is wrong with my program
Use this code to solve your problem...
ViewController.m
- (void)viewDidLoad
{
NSThread *myThread =[[NSThread alloc]initWithTarget:self selector:#selector(doParsing) object:nil];
[myThread start];
[super viewDidLoad];
}
-(void)doParsing
{
xmlParser =[[XMLParser alloc]init];
[xmlParser loadXML];
}
Instead of creating a NSThread object you can start a thread using
//performSelectorInBackground:withObject: is NSObject's method
[self performSelectorInBackground:#selector(loadXML) withObject:nil];
I didn't find any buggy code but enable NSZombie and seee which object is causing this.
loadXML is not define on ViewController so your thread code should be changed to use an instance of XMLParser instead of self like so:
XMLParser *parser = [[XMLParser alloc] init];
NSThread *thread = [[NSThread alloc] initWithTarget:parser selector:#selector(loadXML) object:nil];
[thread start];
Since Apple introduced GCD, you may solve it without creating any NSThread instance.
dispatch_async(dispatch_get_global_object(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self loadXML];
});
Related
First of all, I'd like to say that I'm really having a bad time trying to configure and use my SQLite DB in a background thread so that the main thread is not blocked.
After I found a little guide somewhere on the Internet, I've decided to go for the FMDB wrapper.
All the methods related to the DB operations are in the same class and this is where I'm getting errors:
I've set the static variables like this:
static FMDatabaseQueue *_queue;
static NSOperationQueue *_writeQueue;
static NSRecursiveLock *_writeQueueLock;
Then in my init method I have:
- (id)init {
self = [super init];
if (self) {
_queue = [FMDatabaseQueue databaseQueueWithPath:[self GetDocumentPath]];
_writeQueue = [NSOperationQueue new];
[_writeQueue setMaxConcurrentOperationCount:1];
_writeQueueLock = [NSRecursiveLock new];
}
return self;
}
And this is the method that gives me the error:
- (void)UpdateTime:(NSString *)idT :(int)userId {
[_writeQueue addOperationWithBlock:^{
[_writeQueueLock lock];
[_queue inDatabase:^(FMDatabase *dbase) {
AppDelegate *deleg = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if (![dbase executeUpdate:#"update orari set orario=datetime(orario, '? minutes') where nome=? and dataid>=? and idutente=?"
withArgumentsInArray:#[[NSNumber numberWithFloat:deleg.diff], deleg.nome, [NSNumber numberWithInt:deleg.idMed], [NSNumber numberWithInt: userId]]]) {
NSLog(#"error");
}
}];
[_writeQueueLock unlock];
}];
[_writeQueue addOperationWithBlock:^{
[_writeQueueLock lock];
[_queue inDatabase:^(FMDatabase *dbase) {
AppDelegate *deleg = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if (![dbase executeUpdate:#"UPDATE orari SET presa=1 where dataid=? and idutente=?"
withArgumentsInArray:#[[NSNumber numberWithInt:deleg.identific], [NSNumber numberWithInt: userId]]]) {
NSLog(#"error");
}
}];
[_writeQueueLock unlock];
}];
[self AddNotification];
}
These are the errors I'm getting:
*** -[NSRecursiveLock dealloc]: lock (<NSRecursiveLock: 0xc38b350> '(null)') deallocated while still in use
DB Error: 5 "database is locked"
*** -[NSRecursiveLock unlock]: lock (<NSRecursiveLock: 0x13378d20> '(null)') unlocked when not locked
From the guide I've read, I supposed that the access to my DB would have been "serialized", and each update would have been added to a queue and executed one at a time.
As you can see, I have a lot to learn about this topic, so any help would really be appreciated.
As I can See you have not created shared instance or singleton instance of this init call
- (id)init {
self = [super init];
if (self) {
_queue = [FMDatabaseQueue databaseQueueWithPath:[self GetDocumentPath]];
_writeQueue = [NSOperationQueue new];
[_writeQueue setMaxConcurrentOperationCount:1];
_writeQueueLock = [NSRecursiveLock new];
}
return self;
}
This should be a singleton call as you will create multiple instance of NSOperationQueue which will make DB vulnurable in a multi-threaded environment, try making it singleton call for your database either using GCD or
static DBManager *sharedInstance = nil;
+(DBManager*)getSharedInstance{
if (!sharedInstance) {
sharedInstance = [[super allocWithZone:NULL]init];
_queue = [FMDatabaseQueue databaseQueueWithPath:[self GetDocumentPath]];
_writeQueue = [NSOperationQueue new];
[_writeQueue setMaxConcurrentOperationCount:1];
_writeQueueLock = [NSRecursiveLock new];
}
return sharedInstance;
}
It might solve your problem and this is first time I am answering here and I am new to the environment so please be little bit forgiving :) Thanks
In my app, I have my main file that creates a new instance of a class and then uses NSOperationQueue to run the class functions in the background, like so:
NSOperationQueue backgroundQueue = [NSOperationQueue new];
MyClass mc = [MyClass alloc];
NSInvocationOperation* operation = [[NSInvocationOperation alloc] initWithTarget:mc selector:#selector(runEvents) object:nil];
[backgroundQueue addOperation:operation];
MyClass then does stuff in RunEvents, but I'm having difficulty passing data to the UI. I'm just trying to update a label on my storyboard, which I can do in my main class that calls MyClass, but how do I update it from MyClass?
The typical answer is to create your class as a NSOperation subclass and give it a custom completion block. If your goal is update the UI or some model object in the completion block, make sure to dispatch that block back to the main queue:
// CustomOperation.h
#import <Foundation/Foundation.h>
typedef void(^CustomOperationCompletion)(NSString *string);
#interface CustomOperation : NSOperation
#property (nonatomic, copy) CustomOperationCompletion customOperationCompletion;
- (id)initWithCustomCompletion:(CustomOperationCompletion)completion;
#end
and
// CustomOperation.m
#import "CustomOperation.h"
#implementation CustomOperation
- (id)initWithCustomCompletion:(CustomOperationCompletion)completion {
self = [super init];
if (self) {
self.customOperationCompletion = completion;
}
return self;
}
- (void)main {
NSLog(#"%s starting", __FUNCTION__);
sleep(5);
NSString *string = [[NSDate date] description];
if (self.customOperationCompletion) {
[[NSOperationQueue mainQueue] addOperationWithBlock: ^{
self.customOperationCompletion(string);
}];
}
NSLog(#"%s ending", __FUNCTION__);
}
#end
Then you can invoke it with something like:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
CustomOperation *operation = [[CustomOperation alloc] initWithCustomCompletion:^(NSString *string) {
// update the UI with the results of the operation; here I'm just going to log it
NSLog(#"all done, string=%#", string);
}];
[queue addOperation:operation];
Clearly, change your CustomOperationCompletion parameters to include whatever you want to return (I'm just passing a string back).
im not able to display the values from this code .plz provide a code to display the mutabledictionay and a
- (void)viewDidLoad{
[super viewDidLoad];
mdict =[[NSMutableDictionary alloc]init];
[mdict setValue:#"abc" forKey:#"def"];
[mdict release];
}
-(void)display{
CFShow(mdict);
}
What about using
-(void)display{
NSLog(#"%#",mdict);
}
Change your method as:
- (void)viewDidLoad{
[super viewDidLoad];
mdict =[[NSMutableDictionary alloc]init];
[mdict setValue:#"abc" forKey:#"def"];
//if you want to display use following statement
[self display];
// [mdict release];//you should not release it here.
}
NOTE: In viewDidLoad you are using [mdict release]; mdict will be released!!!
this should not be in viewDidLoad, put that statement in dealloc.
First You need to create NSMutableDictionary is Public (declare in .h file) because you use it in outside and release its instance in dealloc method
- (void)viewDidLoad{
[super viewDidLoad];
self.mdict =[[NSMutableDictionary alloc]init];
[self.mdict setValue:#"abc" forKey:#"def"];
[self display];
}
-(void)display
{
NSLog(#"%#",[self.mdict objectForKey:#"def"]);
}
and release instance of dictionary in -(void)dealloc method
XCode 4.5.2; I'm downloading an image from a remote server like this :
- (void)viewDidLoad
{
[super viewDidLoad];
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage)
object:nil];
[queue addOperation:operation];
}
- (void)loadImage{
self.theobject = [RemoteQuery loadObjectWithImage:self.imageKey];
[self performSelectorOnMainThread:#selector(displayImage) withObject:nil waitUntilDone:YES];
}
-(void)displayImage{
UIImage *image = [UIImage imageWithData: self.theobject.imageData];
[self.imageView setImage:image];
}
This works fine on IOS simulator, but doesn't work on a device; it seems like displayImage is called before the data is loaded from [RemoteQuery loadImage]. What would be the best way to ensure that the image has loaded properly before showing it ?
Create a delegate protocol which will call back to the original object when the image download finishes. This NSOperation tutorial has more details on how to do this
Alternatively, use the NSOperation's completionBlock to perform the image display.
I have a problem getting a UIActivityIndicatorView to show when I collect data from a server with help from the NSURLConnection request.
The request I think is asynchronous, i.e., started in a new thread. I have copied from Apple's AdvancedTableViewCells example. And I run it in XCode in the iOS 4.3 iPhone simulator. I have not tested it on a real iPhone yet.
Also I have googled this problem and tried a lot of suggestions but the feeling is that I have forgotten something basic. Below is my code from the class RootViewController.
I just select a row, create and add the activityview, startanimating, and then create the NSUrlConnection object which starts to fetch data from the server in another thread, I believe.
Any ideas?
#interface RootViewController : UITableViewController {
NSMutableData *receivedData;
UIActivityIndicatorView *activityView;
}
#end
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// In my rootviewcontroller
activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[self.view addSubview:activityView];
[activityView startAnimating];
…
NSMutableURLRequest *tUrlRequest = [tQuery createUrlRequest:tStatId];
NSURLConnection *tConnectionResponse = [[NSURLConnection alloc] initWithRequest: tUrlRequest delegate: self];
if (!tConnectionResponse) {
NSLog(#"Failed to submit request");
} else {
NSLog(#"Request submitted");
receivedData = [[NSMutableData data] retain];
}
return;
}
...
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
NSXMLParser *tParser = [[NSXMLParser alloc] initWithData: receivedData];
...
[tParser parse];
...
[connection release];
[receivedData release];
[NSThread sleepForTimeInterval: 2.0]; // Just to see if activity view will show up...
NSUInteger row = 1;
if (row != NSNotFound)
{
// Create the view controller and initialize it with the
// next level of data.
VivadataTViewController *vivaViewController = [[VivadataTViewController alloc] init];
if (activityView != nil) {
[activityView stopAnimating];
}
}
}
Had the same exact issue, try to change the color of the UIActivityIndicatorView under Attributes Inspector -> Style to Gray