I'm having a crash but only in the ad hoc version. The debug build works fine but the adhoc crashes. This is being compiled with ARC but to use this library I have "-fno-objc-arc" set for compiler flags. Crash report is here: http://pastebin.com/edasCJbb
-(void)executePostRequestWithEndpoint:(NSString *)pathMethod usingVariables:(NSDictionary *)dict completion:(BWObjectBlock)completion failure:(BWFailureBlock)failure {
NSURL *url = [NSURL URLWithString:pathMethod];
__unsafe_unretained __block ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
NSLog(#"It gets to this NSLog and then crashes");
[request addRequestHeader:#"User-Agent" value:kMyUserAgent];
NSLog(#"It DOES NOT get to this NSLog");
NSMutableDictionary *params = dict ? [NSMutableDictionary dictionaryWithDictionary:dict] : [NSMutableDictionary dictionary];
if (params.count > 0) {
for (NSString *key in [params allKeys]) {
[request setPostValue: [[[params objectForKey:key] description] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] forKey: key];
}
}
[request setCompletionBlock:^{
id json =[[request responseString] JSONValue];
if ([json isKindOfClass:[NSDictionary class]]) {
completion(json);
}else{
failure(json,nil);
}
}];
[request setFailedBlock:^{
id o = [[request responseString] JSONValue];
failure(o,request.error);
}];
[request startAsynchronous];
}
I fully admit that I don't really understand exactly what those compiler flags do or what the __unsafe_unratained __block does either. But I'm assuming that request is being immediately released and then bad access when used. This method is crashing on the first use in the app, but normally could get called several times in a row to access different things from my server, log in, etc. So I can't use a property for that request as it would get overwritten on the 2nd request.
Of course this is using ASIHttpRequest library from Ben Copsey which is not ARC while the rest of my app is.
Xcode 5.0
Tested and crashes on all devices from iPhone4S to 5S - but only when compiled under Archive. Debug builds don't crash.
Deployment target is 5.0 but could be raised to 6.0 if it would help.
Just hoping that someone can explain this __unsafe... stuff to me and help me figure out how to fix this.
UPDATE- The crash was solved by using this answer:
ASIHTTPRequest / ASIFormDataRequest - referencing request object within blocks under ARC
But the block isn't working. Still is working different on a debug build than on a ad hoc build, which is a PITA.
I changed:
__unsafe_unretained __block ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
to:
ASIFormDataRequest * __weak request = [ASIFormDataRequest requestWithURL:url];
And variable is now retained long enough to prevent a crash. But what gets returned to the caller is either NULL or it never comes out of it.
Related
So my app begins on first run by parsing all the information in a json file (included in the project) and saves that into its core data model.
This runs fine via debugging deployment with XCode however when I install the app via Testflight, it crashes immediately.
I have identified it to be the parsing of the json file that is the problem as I have created a build that does not do this & instead grabs the data straight from a web api, the only problem with this is that from the web api it will take about an hour to download all the data, from the json file, it takes about a minute.
I have tried disabling BITCODE & ensuring that the scheme is set to Release, which seems to cover most of these start up problems via Testflight. Neither has worked.
My suspicion is that the json file has not correctly been packaged with the app when distributed via Testflight, but i have no idea how to remedy this. Does anyone have any suggestions?
I am including my import function below incase the error is contained within this and not the configuration.
The json file is roughly 26mb which is very large compared to most other files in the project.
My device is an iPhone X running iOS 11.2.6 and XCode 9.2,
the app also successfully runs on all simulators.
I am using Objective C
-(void)ImportInitialCards:(NSManagedObjectContext *) managedObjectContext
{
_privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
// Configure Managed Object Context
[_privateManagedObjectContext setParentContext:managedObjectContext];
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"cardDatabase1" ofType:#"json"];
NSInputStream *inputStream = [[NSInputStream alloc] initWithFileAtPath:filePath];
[inputStream open];
NSArray *cards = [NSJSONSerialization JSONObjectWithStream:inputStream options:kNilOptions error:nil];
float percentage = 1.0 / (float) cards.count;
for (NSDictionary *card in cards)
{
NSString *cardParticularsJson = [card valueForKey:#"cardContent"];
NSData *cardParticularsData = [cardParticularsJson dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *cardParticulars = [NSJSONSerialization JSONObjectWithData:cardParticularsData options:NSJSONReadingMutableContainers error:nil];
NSString *cardName = [cardParticulars valueForKey:#"name"];
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Card"];
[request setPredicate:[NSPredicate predicateWithFormat:#"name == %#", cardName]];
NSError *error = nil;
NSUInteger count = [_privateManagedObjectContext countForFetchRequest:request error:&error];
if (count > 0)
{
NSLog(#"CardMatched: %#", cardName);
//card matched
_progress += percentage;
_currentProgressDescription = #"Scanning ...";
}
else
{
_currentProgressDescription = [NSString stringWithFormat:#"Importing: %#", cardName];
NSManagedObject *newCard = [NSEntityDescription insertNewObjectForEntityForName:#"Card" inManagedObjectContext:_privateManagedObjectContext];
[self SaveCardFrom:cardParticulars to:newCard saveThumb:NO inContext:_privateManagedObjectContext];
_progress += percentage;
dispatch_async(dispatch_get_main_queue(),^ {
NSError *error = nil;
[managedObjectContext save:&error];
} );
}
}
}
I've decided to post the solution to my problem in the hope that it helps someone else that struggled like me.
So while importing the JSON file I was updating a progress bar to indicate how long it would take, this was in a while loop that was maxing out the CPU, that along with the JSON import sent the CPU to approx 200% which caused the app to close.
The solution seems quite obvious really, don't make the cpu go above 100%
I now plan to only update the progress bar when the value is changed rather than constantly updating via a while loop.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSURL *site_url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/json/data/post?sid=%#", SECURE, PASSCODE]];
NSData *jsonData = [NSData dataWithContentsOfURL:site_url];
NSError *error = nil;
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
self.items = dataDictionary;
}
I am trying to parse json data. It works fine with data from the live server. However, when I change the link to http://localhost:8090. It stops working.
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'data parameter is nil'
I can access it from the data from the web browser. Does anyone know why is that?
Does it work on emulator and not on a real device?
You should never use localhost when developing apps, use the local IP for the server instead. Localhost is the machine who make the call to the server. When you try on the emulator and you have the server on the same machine it works because they are the same.
But when you try on a real device, localhost is the device, and the device doesn't have a server installed, so it will fail.
BTW, to test on a real device, it has to be connected to the same network.
What you need here is to implement the NSURLConnection and receive data from it
Check out this
NSURL *site_url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/json/data/post?sid=%#", SECURE, PASSCODE]];
NSURLRequest *req = [NSURLRequest requestWithURL:site_url];
NSURLConnection *con = [[NSURLConnection alloc] initWithRequest:req delegate:self];
[con start];
and from the delegates get the response
this document can help you a lot in this
I am currently developing an iOS application and am implementing the Box.Net SDK. I have gotten everything to work except the ability to move files around, which is not a native feature of the SDK. I am trying to twist my way through it.
If you are familiar with the structure of Box.Net, each file/folder has an ID number for itself, and an ID its parent. From what I understand if I want to move a file, I am supposed to change the parent ID number on the file which will point it to the new location. I can't seem to get it to work properly though. My application seems to keep crashing.
This is what I have so far, generalized.
BoxObject *boxObject = [[[Box objectWithID:(ID#ofParent)] children] objectAtIndex:i];
[boxObject parent].boxID = 0; // <-- Problem (causes crash)
I also tried this.
[boxObject setParent:[Box folderWithID:[BoxID numberWithInt:i]]];
The boxObject variable is the file that I want to move. I am setting its parent ID equal to 0, which is supposed to be the root folder. However, my application crashes when I try to reassign the parent ID for the file. Any ideas on how to successfully move files/folders? Any help is much appreciated! Thanks in advance!
Okay. I suppose there wasn't a way to do fix this in-house with the SDK. So, I had to send out an external PUT request. I used the following code to handle moving files.
- (void)moveItem:(BoxObject *)object toParentFolderWithID:(BoxID *)parentID
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://api.box.com/2.0/files/%#", object.boxID]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"PUT"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *auth = [NSString stringWithFormat:#"BoxAuth api_key=%#&auth_token=%#",[Box boxAPIKey],[defaults objectForKey:#"box-api-auth-token"]];
NSString *payload = [NSString stringWithFormat:#"{\"parent\": {\"id\": %#}}", parentID];
[request setHTTPBody:[NSMutableData dataWithData:[payload dataUsingEncoding:NSUTF8StringEncoding]]];
[request setValue:auth forHTTPHeaderField:#"Authorization"];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
[connection start];
}
Just as a reminder if you are new to the Box SDK, you will most likely need to update/refresh the data after moving the files. If not handled, your application could crash if the file doesn't exist. Hope this helps to anyone was not sure about this.
I'm developping a little image sharing app for my company. Everything works pretty fine except for one thing : when I upload an image to the server, and switch the app to background, a part of the image is corrupted (all gray).
It seems that the image data is sent correctly as long as the app is live. As soon as I switch to background, it sends nothing as it seems.
For the record, I use ASIHttpRequest, the shouldContinueWhenAppEntersBackground is set to YES and I'm running the app from iOS 4.3 to iOS 6.0. I'm using ARC.
I tried to "retain" (through a strong reference) both the image and the data, nothing there too.
Here are parts of the code :
The
Webservice that sends the image
- (void)sendImage:(UIImage*)image forEmail:(NSString*)email
{
NSString* uploadImage = [NSString stringWithFormat:[self completeUrlForService:SEND_PHOTO], email];
NSURL* url = [NSURL URLWithString:[uploadImage stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSLog(#"uploadImage %#", uploadImage);
// setting that we will send a JSON object
[self setRequestType:WebServiceWrapperTypePOSTRequest];
// when posting a picture, it could take more time...
self.request.timeOutSeconds = 4*60;
[self.request setShouldContinueWhenAppEntersBackground:YES];
// setting up the POST data
[self addPostData:image forKey:#"fileContents"];
// start the request
[self startRequestForUrl:url userInfo:[NSDictionary dictionaryWithObject:SEND_PHOTO forKey:URL_KEY]];
}
the actual part of ASIHttpRequest class
self.request = [ASIHTTPRequest requestWithURL:url];
[self.request setShouldContinueWhenAppEntersBackground:YES];
NSString* key = [[self.postDictionnary allKeys] objectAtIndex:0];
UIImage* value = [self.postDictionnary valueForKey:key];
__strong NSData* data = UIImageJPEGRepresentation(value, 1.0);
if (!data) data = UIImagePNGRepresentation(value);
[self.request appendPostData:data];
[self.request setPostLength:data.length];
[self.request setUserInfo:userInfo];
[self.request setDelegate:self];
[self.request startAsynchronous];
If any of you guys has the tinyest idea, I'll take it!
Thanks.
Finally I decided to use a different library (MKNetworkKit) and instead of sending an UIImage, I save the image on disk to the tmp folder and send the file instead. When the download is complete, I just delete the image on disk. It worked liked a charm :)
Here's a leak problem that I'm having trouble with. Most of this code is just here for context so you can see that the "response" NSData object is not what's leaking.
If I drill down into the touchJSON code, following the stack trace as given to me by the LEAKS tool, the leak apparently begins life at the line
*outStringConstant ....
But since this is such a commonly used library, I doubt it's the problem.
One note. This doesn't leak the first time it's executed, only every subsequent time. But it leaks a lot, so the response data is probably the actual data that's leaking.
Also, if anyone is familiar with touchJSON and this code, can you explain to me what this outStringConstant variable is and what it does? It doesn't appear to play any role, other than to be assigned a copy of theString, though if I remove that line the code crashes.
MY CODE is
dataRequestURL = [NSString stringWithFormat:#"http://www....", ...];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:dataRequestURL] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:&ts_response error:&ts_error];
NSArray *array = [[CJSONDeserializer deserializer] deserialize:response error:nil]; <- LEAKS HERE
TOUCHJSON CODE is
-(BOOL)scanJSONStringConstant:(NSString **)outStringConstant error:(NSError **)outError {
NSMutableString *theString = [[NSMutableString alloc] init];
if (outStringConstant != NULL) { *outStringConstant = [[theString copy] autorelease]; }
[theString release];
}