I wrote a program that worked as a server.
Knowing that "accept" was blocking the program.
I wanted to launch a thread with this statement to prevent precisely that the program blocked, but this still happens.
Can anybody help?
Post code
Thanks
-(IBAction)Connetti{
if(switchConnessione.on){
int port = [fieldPort.text intValue];
labelStatus.text = [[NSString alloc] initWithFormat:#"Il Server è attivo"];
server_len = sizeof(server);
server.sin_family = AF_INET;
server.sin_port = htons((u_short)port);
server.sin_addr.s_addr = INADDR_ANY;
sd = socket (AF_INET, SOCK_STREAM, 0);
bind(sd, (struct sockaddr*)&server, sizeof(server));
listen(sd, 1);
[NSThread detachNewThreadSelector:#selector(startThreadAccept) toTarget:self withObject:nil];
}
else {
labelStatus.text = [[NSString alloc] initWithFormat:#"Server non attivo"];
switchChat.on = FALSE;
switchChat.enabled = FALSE;
}
}
-(void)startThreadAccept{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
[self performSelectorOnMainThread:#selector(acceptConnection) withObject:nil waitUntilDone:NO];
[pool release];
}
-(void)acceptConnection{
new_sd = accept(sd, (struct sockaddr*)&server, &server_len);
labelStatus.text = [[NSString alloc] initWithFormat:#"Ho accettato una connessione:%d", new_sd];
switchChat.enabled = TRUE;
}
You still call accept() on the main thread. If you want the connection to be accepted on a different thread, then you need to remove the -performSelectorOnMainThread: call.
this is my new methods
-(IBAction)Connetti{
//code
[NSThread detachNewThreadSelector:#selector(acceptConnection) toTarget:self withObject:nil];
//code
}
-(void)acceptConnection{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
new_sd = accept(sd, (struct sockaddr*)&server, &server_len);
labelStatus.text = [[NSString alloc] initWithFormat:#"Ho accettato una connessione:%d", new_sd];
switchChat.enabled = TRUE;
[pool release];
}
It 's a correct solution? Why in some occasions, the thread seems to not start? Thanks
Related
What i am doing is applying push view controller to move to next view from table view's didSelectMethod. And on next view controller data is fetched for that view. So, the problem is the view switches only when the data is fetched completely, and it contains images and text both. But i have already applied the lazy loading for images but the issue is to move to next view immediately and then fetch data and update the UI and tableview. Below is code i am trying.
On next view controller's didLoad method.
[NSThread detachNewThreadSelector:#selector(setImage) toTarget:self withObject:nil];
the method setImage fetching all data images and text.
-(void)setImage
{
if([type isEqualToString:#"Organisation"])
{
self.mGetDataDict = [MyEventApi members:self.mUserIdDict];
self.mRecievedDataDict = [self.mGetDataDict valueForKey:#"members"];
}
if([type isEqualToString:#"Individual"]){
self.mGetDataDict = [MyEventApi friends:self.mUserIdDict];
self.mRecievedDataDict = [self.mGetDataDict valueForKey:#"friends"];
}
if([self.mGetDataDict valueForKey:#"friends"] == [NSNull null])
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"alert" message:#"You have not added any friend yet." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
else
{
self.mFrndNameArr = [[NSMutableArray alloc]init];
self.mFrndImgArr = [[NSMutableArray alloc]init];
self.mFirstNameArr = [[NSMutableArray alloc]init];
self.mLastNameArr = [[NSMutableArray alloc]init];
self.mFrndIdArr = [[NSMutableArray alloc]init];
self.mFrndMSinceArr = [[NSMutableArray alloc]init];
self.mFrndDescArr = [[NSMutableArray alloc]init];
self.mFrndNameArr = [self.mRecievedDataDict valueForKey:#"username"];
self.mFrndImgArr = [self.mRecievedDataDict valueForKey:#"image"];
self.mFirstNameArr = [self.mRecievedDataDict valueForKey:#"firstName"];
self.mLastNameArr = [self.mRecievedDataDict valueForKey:#"lastName"];
self.mFrndIdArr = [self.mRecievedDataDict valueForKey:#"id"];
self.mFrndMSinceArr = [self.mRecievedDataDict valueForKey:#"memberSince"];
self.mFrndDescArr = [self.mRecievedDataDict valueForKey:#"description"];
[self.mFriendsTable reloadData];
}
}
Please guide for above, is i am using correct method or there is another way to do this.
Thanks in advance.
Please use GCD :)
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
//in this scope load your data from server
dispatch_async(dispatch_get_main_queue(), ^{
//use this scope to reload UI with data received from scope above
// in your case this is NSDictionary object, this object will be able to use in this scope because this scope will catch variables from scope above
});
});
you can use GCD
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
//Fire api
dispatch_async(dispatch_get_main_queue(), ^{
//update ui
});
});
I would recommend against using the NSThread API in your context. API like GCD or NSOperation are sitting at a higher level and will provide you with the solution you are looking for:
An implementation with GCD will look like this
dispatch_queue_t backgroundQueue = dispatch_queue_create("backgroundQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(backgroundQueue, ^{
// update your method to remove the table refresh
[self setImage];
dispatch_async(dispatch_get_main_queue(), ^{
//Update the UI on the main thread
[self.mFriendsTable reloadData];
});
I'm stuck at this method and I don't know why!
Can anyone point me to some source code?
Thank you so much!
This is my source code:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
.......
readData = [readFileHandle readDataOfLength:defaultLen]
NSData *decryptedData = nil;
//check is last buffer of file
NSUInteger exLen = [readData length] % 16;
NSUInteger decryptionLen = [readData length] - exLen;
NSData *dataForDecryption = nil;
if(exLen != 0)
{
stuck at here-> [readData getBytes:dataForDecryption length:decryptionLen];
//
decryptedData = [dataForDecryption AES256DecryptWithKey:KEY];
self.isEndOfFile = YES;
}
else
decryptedData = [readData AES256DecryptWithKey:KEY];
[readFileHandle closeFile];
.......
[pool drain];
I've used some functions such as:
NSData *dataForDecryption = [[[NSData alloc] initWithBytes:readData length:decryptionLen]autorelease];
NSData *dataForDecryption = [NSData dataWithBytes:readData length:decryptionLen];
But I get the same error.
When i'm using
dataForDecryption = [readFileHandle readDataOfLength:decryptionLen];
it's stuck at pos above and the size read is 0, although it's not EOF.
Thanks
stuck at here-> [readData getBytes:dataForDecryption length:decryptionLen];
You're passing dataForDecryption, which is a NSData*, but the parameter is supposed to be a buffer, i.e. void*. If you want a NSData*, you should instead use a method like subdataWithRange:.
dataForEncryption = [readData subdataWithRange:NSRangeMake(0, decryptionLen)];
I am trying to add data to CoreData. It works fine when I build from Xcode to the phone but when I try to start the app directly from iPhone it crashes on first save to the Context.
I read a text file that is synced via iTunes File Sharing, the file is pretty big (~350 000 lines). The values I get from the file is added to two different arrays (barcodes and productNames). The arrays are later batched through and the sent to the function where I save the data.
From the array loop:
[...]
words = [rawText componentsSeparatedByString:#";"];
int loopCounter = 0;
int loopLimit = 20000;
int n = 0;
int wordType;
NSEnumerator *word = [words objectEnumerator];
NSLog(#"Create arrays");
while(tmpWord = [word nextObject]) {
if ([tmpWord isEqualToString: #""] || [tmpWord isEqualToString: #"\r\n"]) {
// NSLog(#"%#*** NOTHING *** ",tmpWord);
}else {
n++;
wordType = n%2;
if (wordType == kBarcode) {
[barcodes addObject: tmpWord];
}else if (wordType == kProduct) {
[productNames addObject: tmpWord];
}
// Send to batch //
loopCounter ++;
if (loopCounter == loopLimit) {
loopCounter = 0;
NSLog(#"adding new batch");
[self addBatchOfData];
[barcodes release];
[productNames release];
barcodes = [[NSMutableArray arrayWithCapacity:20000] retain];
productNames = [[NSMutableArray arrayWithCapacity:20000] retain];
}
}
[...]
And then the save-function:
-(void)addBatchOfData {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSError *error;
NSUInteger loopLimit = 5000;
NSUInteger loopCounter = 0;
NSString *ean;
NSString *designation;
for (int i=0; i<[barcodes count];i++ ) {
ean = [barcodes objectAtIndex:i];
designation = [productNames objectAtIndex:i];
Product *product = (Product *)[NSEntityDescription insertNewObjectForEntityForName:#"Product" inManagedObjectContext:importContext];
[product setDesignation:designation];
[product setBarcode:ean];
loopCounter ++;
if (loopCounter == loopLimit) {
NSLog(#"Save CoreData");
[importContext save:&error];
[importContext reset];
[pool drain];
pool = [[NSAutoreleasePool alloc] init];
loopCounter = 0;
}
}
// Save any remaining records
if (loopCounter != 0) {
[importContext save:&error];
[importContext reset];
}
[pool drain];
}
It's really irritating that it works fine when I build from Xcode. Hopefully there is a setting that I missed or something...
EDIT: Forgot to mention that I don't get passed the Default-screen and I don't have any logs. Can it have something to do with the provisioning?
Offload your file loading in a background thread and let the phone start up your main window and view. iOS will kill your app if you do not present a view in a timely manor (this is what you are seeing).
I have to do something like this for my xml -> CoreData converter code. I just present the user with a view notifying them of what is going on and a progress bar (I use https://github.com/matej/MBProgressHUD).
something like:
self.hud = [[MBProgressHUD alloc] initWithView:window];
// Set determinate mode
hud.mode = MBProgressHUDModeDeterminate;
hud.delegate = self;
hud.labelText = #"Converting Data File";
[self.window addSubview:hud];
// Show the HUD while the provided method executes in a new thread
[hud showWhileExecuting:#selector(convertToCoreDataStoreTask) onTarget:self withObject:nil animated:YES];
You just have to make sure that you use a separate NSManagedObjectContext in the new thread.
I would suggest that you implement this delegate method and then try to see what is going on with memory.
when running in the simulator, you have no memory constraints, but when running in the phone you do
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
}
I think I find the solution to my question.
What I was doing was that I started all the heavy data crunch in the "- (void) viewDidLoad {". When I changed it to start the crunch after I clicked a button in the app, it worked just fine.
Right now it's just finding out where the start the data crunch, any suggestions?
how can i detect that received sms is read or not by user, i am using CTMessageCenter header also pleas help me..
and also tell me how can i put my application in background continuously....
i think there is no method from which we can found that message is read or not in non jailbreak ...
Ya you can read your incoming message and send also.In your main.m write this code and use three files:CoreTelephony.h,CTMessage.h,CTMessageCenter.h
One problem with this using this way you can't submit your app on app store.
static void callback(CFNotificationCenterRef center, void *observer, NSString* name, const void *object, NSDictionary* info) {
fprintf(stderr, "Notification intercepted: %s\n", [name UTF8String]);
if([name isEqualToString:#"kCTMessageReceivedNotification"] && info)
{
NSNumber* messageType = [info valueForKey:#"kCTMessageTypeKey"];
if([messageType isEqualToNumber:[NSNumber numberWithInt:1]])
{
NSNumber* messageID = [info valueForKey:#"kCTMessageIdKey"];
CTMessageCenter* mc = [CTMessageCenter sharedMessageCenter];
CTMessage* msg = [mc incomingMessageWithId:[messageID intValue]];
NSObject<CTMessageAddress>* phonenumber = [msg sender];
NSString *senderNumber = (NSString*)[phonenumber canonicalFormat];
NSString *sender = (NSString*)[phonenumber encodedString];
CTMessagePart* msgPart = [[msg items] objectAtIndex:0]; //for single-part msgs
NSData *smsData = [msgPart data];
NSString *smsText = [[NSString alloc] initWithData:smsData encoding:NSUTF8StringEncoding];
fprintf(stderr, "SMS Message from %s / %s: \"%s\"\n",[senderNumber UTF8String],[sender UTF8String],[smsText UTF8String]);
}
}
return;
}
int main(int argc, char **argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id ct = CTTelephonyCenterGetDefault();
CTTelephonyCenterAddObserver(ct, NULL, callback, NULL, NULL, CFNotificationSuspensionBehaviorHold);
// Start the run loop. Now we'll receive notifications.
[[NSRunLoop currentRunLoop] run];
NSLog(#"you are in main thread");
[pool drain];
printf("Unexpectedly back from CFRunLoopRun()!\n");
[pool release];
}
I call a function with performSelectorInBackground, and in this function, I declare
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
at the beginning
[pool release];
at the end
But in the console, I have this message:
2010-07-23 10:58:30.277 ProjetMission[5914:6913] void _WebThreadLockFromAnyThread(bool), 0x5d5c770: Obtaining the web lock from a thread other than the main thread or the web thread. UIKit should not be called from a secondary thread.
Why? Because if I don't put a nsautoreasepool in my function I have a lot of message like this:
2010-07-23 11:02:58.667 ProjetMission[5951:660f] *** __NSAutoreleaseNoPool(): Object 0x5a7c560 of class NSCFString autoreleased with no pool in place - just leaking
thanks for your help
-(void) telechargerDossierWebDansThread
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *nomFichier;
int i;
BOOL dossierExiste = FALSE;
int y;
NSString *reponse;
NSArray *listeFichier = [self listeFichierATelecharger:[dossierWeb stringByAppendingString:#"/fichier-a-downloader.txt"]];
[textView performSelectorOnMainThread:#selector(setText:) withObject:#"" waitUntilDone:YES];
[textView performSelectorOnMainThread:#selector(setText:) withObject:[FonctionUtile concatener: #"Sommaire du download pour le circuit-" chaine2:nomCircuit chaine3:#"" chaine4:#"\n"] waitUntilDone:YES];
[textView performSelectorOnMainThread:#selector(setText:) withObject:[FonctionUtile concatener:textView.text chaine2:#"Nombre de fichier à downloader => " chaine3:[NSString stringWithFormat:#"%d", [listeFichier count]] chaine4:#"\n"] waitUntilDone:YES];
if ([listeFichier count] > 0)
{
if ([ManipulationFichierDossier supprimerDossierFichier:cheminDossierSurIpod] || ![ManipulationFichierDossier VerifierSiDossierFichierExiste:cheminDossierSurIpod] ) {
dossierExiste = [ManipulationFichierDossier creerDossier:cheminDossierSurIpod];
}
if (dossierExiste)
{
[textView performSelectorOnMainThread:#selector(setText:) withObject:[FonctionUtile concatener:textView.text chaine2:[FonctionUtile padderChaine:#"Fichiers à downloader" :27 :#" " :TRUE] chaine3:#"Download succès" chaine4:#"\n" ] waitUntilDone:YES];
y = 70;
for (i = 0; i < [listeFichier count]; i++)
{
nomFichier = [[listeFichier objectAtIndex:i]retain];
if ([self TelechargerFichierUnique:nomFichier :[FonctionUtile concatener:dossierWeb chaine2:#"/" chaine3:nomFichier chaine4:#""] :cheminDossierSurIpod :TRUE])
{
reponse = #"Oui";
}
else
{
reponse = #"Non";
}
[textView performSelectorOnMainThread:#selector(setText:) withObject:[FonctionUtile concatener:textView.text chaine2:[FonctionUtile padderChaine:nomFichier :27 :#" " :TRUE] chaine3:reponse chaine4:#"\n"] waitUntilDone:YES];
y = y +20;
}
}
}
[textView performSelectorOnMainThread:#selector(setText:) withObject:[FonctionUtile concatener:textView.text chaine2: #"Fin du download pour le circuit-" chaine3:nomCircuit chaine4:#""] waitUntilDone:YES];
[pool release];
}
and this function is call by performSelectorInBackground.
Having the NSAutoreleasePool is correct. The error message just seems to indicate that you're manipulating a UI element (a UIWebView, perhaps) from the background thread. As the error message says, this is not A Good Thing™.