NSString EXC_BAD_ACCESS objective C - objective-c

I'm new in Objective C and I have some problem....
It's my code:
1)
testAppDelegate.h (not all):
#interface testAppDelegate : NSObject <NSApplicationDelegate> {
IBOutlet NSWindow *windowLogin;
IBOutlet NSWindow *windowContactList;
IBOutlet NSTextField *memStatus;
NSString *access_token, *expires_in, *user_id;
NSMutableArray *records;}
2) testAppDelegate.m (not all):
int posInStr(NSString *subString, NSString *genString){
NSRange match;
match = [genString rangeOfString:subString];
return match.location;
}
NSString* pars(NSString *str_,NSString *str,NSString *_str){
NSString *tmp;
int startPos = posInStr(str_,str) + [str_ length];
tmp = [str substringFromIndex:startPos];
int finishPos = posInStr(_str, tmp);
return [tmp substringToIndex:finishPos];
}
-(IBAction)but2Click: (id)sender{
NSString *tmp2 = access_token;
NSString *tmp = [NSString stringWithFormat:#"https://api.vkontakte.ru/method/messages.getDialogs?count=3&access_token=%#",tmp2];
NSURL *url = [NSURL URLWithString:tmp];
NSLog(#"%#",tmp);
NSLog(#"%#",url);
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request setDidFinishSelector:#selector(showLoaded)];
[request startAsynchronous];
}
-(IBAction)but1Click:(id) sender{
NSURL *url = [NSURL URLWithString:#"http://api.vkontakte.ru/oauth/authorize?client_id=293&scope=friends,messages&redirect_uri=http://api.vkontakte.ru/blank.html&display=popup&response_type=token"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request setDidFinishSelector:#selector(requestFinishedtest:)];
[request startAsynchronous];
}
- (void)requestFinishedtest:(ASIHTTPRequest *)request
{
[memStatus setStringValue:#"Loading..."];
NSString *tmp = [NSString stringWithFormat:#"%#",[request url]];
[tmp retain];
access_token = pars(#"access_token=", tmp, #"&");
NSLog(#"%#",access_token);
expires_in = pars(#"expires_in=", tmp ,#"&");
user_id = pars(#"user_id=", [NSString stringWithFormat:#"%#&",tmp], #"&");
[memStatus setStringValue:#"Logined"];
[windowLogin orderOut:nil];
[windowContactList makeKeyAndOrderFront:self];
[NSApp activateIgnoringOtherApps:YES];
}
My problem:
"EXC_BAD_ACCESS" in "but2Click"

You are assigning an autoreleased object here:
access_token = pars(#"access_token=", tmp, #"&");
access_token must be getting released before the but2click method is invoked by a button tap.
You need to retain it if you want to use it later.

It's going to be really hard to figure this out from code -- you are going to have to debug it.
I wrote this blog to help understand and debug EXC_BAD_ACCESS
Basically, you are dereferencing a pointer that is pointing to memory that isn't allocated to your process. The main reasons that this could happen are
You are using an object that has been deallocated
The heap is corrupt
The things you should do to debug this:
Do a Build and Analyze. The reports of leaks are bad, but not related to this issue -- you want to look for issues of too few retains
Turn on Zombies and run in the debugger. Now, none of your objects will be deallocated, but when they have a retain count 0, they will complain to the debugger if you use them.
There are other tips on the blog that are a little harder to explain

Related

Strange "zombie" in forwardInvocation: + getArgument:atIndex methods

Here is part from my code:
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect frame = [[UIScreen mainScreen] bounds];
_webView = [[UIWebView alloc] initWithFrame:frame];
[_webView setHidden:NO];
[self.view addSubview:_webView];
_vk = [[DPVkontakteCommunicator alloc] initWithWebView:_webView];
DPVkontakteUserAccount *user;
NSString *accessToken = [[NSUserDefaults standardUserDefaults]
objectForKey:#"accessToken"];
NSInteger userId = [[[NSUserDefaults standardUserDefaults]
objectForKey:#"userId"] integerValue];
user = [[DPVkontakteUserAccount alloc]
initUserAccountWithAccessToken:accessToken
userId:userId];
NSLog(#"%#", user);
[user setSuccessBlock:^(NSDictionary *dictionary)
{
NSLog(#"%#", dictionary);
}];
NSDictionary *options = #{#"uid":#"1"};
// [user usersGetWithCustomOptions:#{#"uid":#"1"}]; // Zombie
[user usersGetWithCustomOptions:options]; // Not zombie
// __block NSDictionary *options = #{};
//
// [_vk startOnCancelBlock:^{
// NSLog(#"Cancel");
// } onErrorBlock:^(NSError *error) {
// NSLog(#"Error: %#", error);
// } onSuccessBlock:^(DPVkontakteUserAccount *account) {
// NSLog(#"account:%#", account);
//
// [account setSuccessBlock:^(NSDictionary *dictionary)
// {
// NSLog(#"%#", dictionary);
// }];
//
// [account docsGetUploadServerWithCustomOptions:options];
// }];
}
and here is the part which processes the userGetWithCustomOptions: method:
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
NSString *methodName = NSStringFromSelector([anInvocation selector]);
NSDictionary *options;
[anInvocation getArgument:&options
atIndex:2];
NSArray *parts = [self parseMethodName:methodName];
NSString *vkURLMethodSignature = [NSString stringWithFormat:#"%#%#.%#",
kVKONTAKTE_API_URL,
parts[0],
parts[1]];
// appending params to URL
NSMutableString *fullRequestURL = [vkURLMethodSignature mutableCopy];
[fullRequestURL appendString:#"?"];
[options enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop)
{
[fullRequestURL appendFormat:#"%#=%#&", key, [obj encodeURL]];
}];
[fullRequestURL appendFormat:#"access_token=%#", _accessToken];
// performing HTTP GET request to vkURLMethodSignature URL
NSURL *url = [NSURL URLWithString:fullRequestURL];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation;
operation = [AFJSONRequestOperation
JSONRequestOperationWithRequest:urlRequest
success:^(NSURLRequest *request,
NSHTTPURLResponse *response,
id JSON)
{
_successBlock(JSON);
}
failure:^(NSURLRequest *request,
NSHTTPURLResponse *response,
NSError *error,
id JSON)
{
_errorBlock(error);
}];
[operation start];
}
problem is that when I am using "options" variable - it works fine, but when using direct values - it fails, app crashes. Using Profile I have found that method call directs to deallocated object.
Why this happens?
There is no other code that can help.
ViewController.m code: https://gist.github.com/AndrewShmig/5398546
DPVkontakteUserAccount.m: https://gist.github.com/AndrewShmig/5398557
The problem is that the parameter of getArgument: is type void *. And you are passing &value, which is NSDictionary * __strong * (pointer to a strong reference) to it. The cast is valid because it is possible to assign any non-object pointer to and from void * without any warnings.
When you pass a "pointer to strong" to a function, that means the function should expect the pointer to a "strong reference", and when the function exits, it should preserve the fact that the pointer points to a "strong reference". What this means is that if the function changes the reference (pointed to by the pointer), it must first release the previous value and then retain the new value.
However, what does getArgument:atIndex: do with its void * argument? It is agnostic about the thing pointed to, and simply copies the value into the memory pointed to. Therefore, it does not do any of this retain and release stuff. Basically, it performs a plain-old pre-ARC non-retaining assignment into your value variable.
So why is it crashing? What is happening is that value is at first nil, and then inside the getArgument:atIndex:, it assigns the new value into it, but it does not retain it. However, ARC assumes that it has been retained, since value is a strong reference. So at the end of the scope, ARC releases it. This is an over-release, since it was never retained.
The solution is to not pass a "pointer to strong" into getArgument:, because that method does not know anything about "strong". Instead, pass a "pointer to unsafe_unretained" or "pointer to void" into it, and then convert it to a strong reference later:
NSDictionary * __unsafe_unretained temp;
[anInvocation getArgument:&temp atIndex:2];
NSDictionary *options = temp; // or you can just use temp directly if careful
or alternately:
void *temp;
[anInvocation getArgument:&temp atIndex:2];
NSDictionary *options = (__bridge NSDictionary *)temp;

EXC_BAD_ACCESS memory error under ARC

In the method below I'm receiving "EXC_BAD_ACCESS" on the line containing the "urlString" variable. My research suggests that this error occurs when the program sends a message to a variable that has already been released. However since I'm using ARC I'm not manually releasing memory. How can I prevent ARC from releasing this variable too soon?
-(NSMutableArray *)fetchImages:(NSInteger *)count {
//prepare URL request
NSString *urlString = [NSString stringWithFormat:#"http://foo.example.com/image?quantity=%#", count];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]];
//Perform request and get JSON as a NSData object
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
//Parse the retrieved JSON to an NSArray
NSError *jsonParsingError = nil;
NSArray *imageFileData = [NSJSONSerialization JSONObjectWithData:response options:0 error:&jsonParsingError];
//Create an Array to store image names
NSMutableArray *imageFileNameArray;
//Iterate through the data
for(int i=0; i<[imageFileData count];i++)
{
[imageFileNameArray addObject:[imageFileData objectAtIndex:i]];
}
return imageFileNameArray;
}
Your problem has nothing to do with ARC. NSInteger isn't a class, so you don't want to be using the %# format. %# is going to send a description method to what the system thinks is an object, but when it turns out not to be one - CRASH. To solve your problem, you have two options:
You might want:
NSString *urlString =
[NSString stringWithFormat:#"http://foo.example.com/image?quantity=%d",
*count];
Make sure the count pointer is valid first!
You might need to change your method signature to be:
-(NSMutableArray *)fetchImages:(NSInteger)count;
and then change the urlString line as follows:
NSString *urlString =
[NSString stringWithFormat:#"http://foo.example.com/image?quantity=%d",
count];
You'll also need to fix all of the callers to match the new signature.
The second option seems more "normal" to me, but without more of your program it's impossible to be more specific.
you also may want to alloc and init the
NSMutableArray *imageFileNameArray;
before adding objects to it, otherwise you'll keep crashing. So you'd have
//Create an Array to store image names
NSMutableArray *imageFileNameArray = [[NSMutableArray alloc] init];

Warnings ASIHttpRequest

i am using ASIHTTPRequest in my iOS APP. i am doing like this :
.h
#interface MyClassr
ASIFormDataRequest *currentRequest;
}
NSURL *url = [NSURL URLWithString:requestUrl];
currentRequest = [ASIFormDataRequest requestWithURL:url];
currentRequest.requestMethod=#"GET";
currentRequest.delegate =self;
[currentRequest setCompletionBlock:^{
listesRestaurants = [XMLParser parseRestaurantResponse:[currentRequest responseData]];
NSLog(#"%#",[currentRequest responseString]);
if (apDelegate.modeGeoloc) {
[map removeAnnotations:map.annotations];
[self addAnnotation];
[self calculDistance];
}
and i have a warnign in the line: [currentRequest setCompletionBlock:^ // Block will be retained by an object strongly retained by the captured object
// Capturing 'self' strongly in this block is likely to lead to a retain cycle
How i can correct this warnind please ?
You need to create a weak reference to self:
__weak MyClassr* blockSelf = self;
and then use that reference in your block:
[blockSelf addAnnotation];
[blockSelf caculDistance];
etc.

objective c how to get placemarks of given coordinates

I have a question related to reverse geo-coding.
In my app, I have some coordinates (not my current coordinates) and I want to convert them into placemarks. I've dug a lot of websites and codes but they are all about reverse geocoding of current location...
Is there any way to get placemarks of specified coordinates (which are not current location)?
And if there is, please help me with some code or references.
You can achieve this in two ways:-
First way:-
Get the info using google api
-(void)findAddresstoCorrespondinglocation
{
NSString *str = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f&sensor=false",myCoordInfo.latitude,myCoordInfo.longitude];
NSURL *url = [NSURL URLWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
[request setRequestMethod:#"GET"];
[request setDelegate:self];
[request setDidFinishSelector: #selector(mapAddressResponse:)];
[request setDidFailSelector: #selector(mapAddressResponseFailed:)];
[networkQueue addOperation: request];
[networkQueue go];
}
in response you will get all information about the location coordinates you specified.
Second Approach:-
Implement reverse geocoding
a.)add mapkit framework
b.)Make instance of MKReverseGeocoder in .h file
MKReverseGeocoder *reverseGeocoder;
c.)in .m file
self.reverseGeocoder = [[MKReverseGeocoder alloc] initWithCoordinate:cordInfo];
reverseGeocoder.delegate = self;
[reverseGeocoder start];
Implement two delegate methods of MKReverseGeoCoder
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error
{
NSLog(#"MKReverseGeocoder has failed.");
}
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark
{
MKPlacemark * myPlacemark = placemark;
NSString *city = myPlacemark.thoroughfare;
NSString *subThrough=myPlacemark.subThoroughfare;
NSString *locality=myPlacemark.locality;
NSString *subLocality=myPlacemark.subLocality;
NSString *adminisArea=myPlacemark.administrativeArea;
NSString *subAdminArea=myPlacemark.subAdministrativeArea;
NSString *postalCode=myPlacemark.postalCode;
NSString *country=myPlacemark.country;
NSString *countryCode=myPlacemark.countryCode;
NSLog(#"city%#",city);
NSLog(#"subThrough%#",subThrough);
NSLog(#"locality%#",locality);
NSLog(#"subLocality%#",subLocality);
NSLog(#"adminisArea%#",adminisArea);
NSLog(#"subAdminArea%#",subAdminArea);
NSLog(#"postalCode%#",postalCode);
NSLog(#"country%#",country);
NSLog(#"countryCode%#",countryCode);
}

Adding Objects from an Array into Core Data

So, for the past two days or so I've been struggling with something that should honestly be a simple task. Here's a little introduction on what I'm trying to achieve.
What I'm doing is utilising a web service of my own, sending a request and parsing the returned JSON with SBJSON. What I know want to accomplish with this parsed JSON is to insert it into Core Data.
I have built a object model already which looks like the following:
#import <CoreData/CoreData.h>
#interface Event : NSManagedObject
{
}
#property (nonatomic, retain) NSString * summary;
#property (nonatomic, retain) NSString * content;
#property (nonatomic, retain) NSDate * updated;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSDate * created;
#property (nonatomic, retain) NSString * ID;
#end
These are all built in regards to what is being parsed, I think I may have to change the NSDate's to NSStrings at a later date, but for now they are NSDates.
So, now to show you what is being parsed. The JSON returns the following.
[{"note id":"525","note title":"Car","note summary":"","note content":"","note created":"1297130179","note_updated":"1297233954"},
{"note id":"252","note title":"Premium Users","note summary":"","note content":"","note created":"1296046367","note_updated":"1296699888"},
{"note id":"253","note title":"Welcome!","note summary":"","note content":"","note created":"1296046367","note_updated":"1296561871"}]
What I am wanting to do is create an entity "Event" and each entity stores the respective values for that event. Easy, right? Obviously not for me.
What I have tried...
NotaciousAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newNote;
newNote = [NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
[newNote setValue:[object valueForKey:#"note title"] forKey:#"title"];
[newNote setValue:[object valueForKey:#"note summary"] forKey:#"summary"];
[newNote setValue:[object valueForKey:#"note updated"] forKey:#"updated"];
NSError *error;
[context save:&error];
Yet this returns an error.
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for attribute: property = "title"; desired type = NSString; given type = __NSArrayI; value = (
Car,
"Premium Users",
"Welcome!"
).'
Any ideas or code samples would help. I really need to get this fixed, all dependent on how this is being stored.
EDIT
Here's how we build the request and parse the string returned.
NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:#"api_key"];
[[LRResty client] get:#"http://notacio.us/api/note" parameters:params withBlock:^(LRRestyResponse *response){
if(response.status == 200) {
NSLog(#"Pulling the users notes \n%#", [response asString]);
// Create SBJSON object to parse JSON
SBJSON *parser = [[SBJSON alloc] init];
// parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
EDIT
Just thought I'd let people know that I'm currently using the Resty RESTful framework to make my calls to my own API. I thought this was the best alternative and easiest way for myself to build a wrapper for it. Here is the full request.
Resty documentation.
-(void)pullNotes {
NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:#"api_key"];
[[LRResty client] get:url parameters:params withBlock:^(LRRestyResponse *response){
if(response.status == 200) {
NSLog(#"Pulling the users notes \n%#", [response asString]);
// Create SBJSON object to parse JSON
SBJSON *parser = [[SBJSON alloc] init];
// parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
NotaciousAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newNote;
newNote = [NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
[newNote setValue:[object valueForKey:#"note title"] forKey:#"title"];
[newNote setValue:[object valueForKey:#"note summary"] forKey:#"summary"];
[newNote setValue:[object valueForKey:#"note updated"] forKey:#"updated"];
NSError *error;
[context save:&error];
}
if (response.status == 404) {
NSLog(#"FAIL\n%#", [response asString]);
}
}];
}
EDIT
So, now that I have fixed the JSON issue and am grabbing the individual strings and such from each array, I'm having issues storing the parsed strings into Core Data.
I'll show you what I currently have.
[newNote ] is the name given to the Core Data entity in the header file of the following.
-(void)pullNotes {
UIApplication *app = [UIApplication alloc];
app.networkActivityIndicatorVisible = YES;
NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:#"api_key"];
[[LRResty client] get:#"http://notacio.us/api/note" parameters:params withBlock:^(LRRestyResponse *response){
if(response.status == 200) {
NSLog(#"Pulling the users notes \n%#", [response asString]);
// Create SBJSON object to parse JSON
SBJSON *parser = [[SBJSON alloc] init];
// parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
NSArray *notes = [object valueForKey:#"result"];
for (NSDictionary *singleNote in notes){
// newNote.created = [singleNote objectForKey:#"note created"]; Need to work on parsing these properly...
// newNote.updated = [singleNote objectForKey:#"note updated"]; Need to work on parsing these properly...
NSString *notetitle = [singleNote objectForKey:#"note title"];
NSString *notesummary = [singleNote objectForKey:#"note summary"];
NSString *noteid = [singleNote objectForKey:#"note id"];
NSString *notecontent = [singleNote objectForKey:#"note content"];
// NSDate *createdDate =
// NSDate *updatedDate =
// If appropriate, configure the new managed object.
[newNote setValue:notetitle forKey:#"title"];
[newNote setValue:notesummary forKey:#"summary"];
[newNote setValue:noteid forKey:#"ID"];
[newNote setValue:notecontent forKey:#"content"];
NSLog(#"value is %#", notetitle);
NSError *error = nil;
if (![newNote.managedObjectContext save:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[tableView reloadData];
app.networkActivityIndicatorVisible = NO;
}
}
if (response.status == 404) {
NSLog(#"FAIL\n%#", [response asString]);
app.networkActivityIndicatorVisible = NO;
}
}];
}
#end
However, running this code doesn't actually store the strings into the Core Data entity. As you can see it isn't finalised, a lot of commented code, but the basis is there. ANYWAY, I'm curious as to whether or not it is how I actually implement this in the pulling of the notes itself from the RootViewController...
In viewDidLoad() I'm calling the following...
ntIndex = [IndexNotes alloc];
ntIndex.api_key = api_key;
ntIndex.tableView = self.tableView;
[ntIndex pullNotes];
[ntIndex release];
[self.tableView reloadData];
}
Any help would be great, I'd love to hear what others think the issue is. I don't get any errors with the above code, just nothing is inserted into the Core Data and in turn isn't displayed in my UITableView in RootViewController...
The first thing I would do is log what this line returns:
[object valueForKey:#"note title"]
You'll find it's not the string you're expecting, but is an array of note titles.
eg:
NSLog(#"value is %#", [object valueForKey:#"note title"]);
Then you'll either need to fix your JSON or change the way you parse it.
Edit:
So when I say fix your JSON, I'm no expert, but I think it should look like this:
{"result":[{"note id":"525","note title":"Car","note summary":"","note content":"","note created":"1297130179","note_updated":"1297233954"}, {"note id":"252","note title":"Premium Users","note summary":"","note content":"","note created":"1296046367","note_updated":"1296699888"}, {"note id":"253","note title":"Welcome!","note summary":"","note content":"","note created":"1296046367","note_updated":"1296561871"}]}
Then:
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
NSArray notes = [object valueForKey:#"result"];
for (NSDictionary *singleNote in notes){
[singleNote objectForKey:"note title"] //this gives you the title of the current note your on
}
It's to do with the fact [object valueForKey:#"note title"] is returning an array.
You'll like want to insert something more like [[object valueForKey:#"note title"] objectAtIndex:1] to take an object out of the array. However working out what index you want to insert from the title array is the hardest part.
Tim
EDIT:
Having looked into some others responses its apparent it's returning all the titles in one object. There's something either incredibly funky going on with your JSON. A way around this would be to possibly for loop over your results set from your JSON request and using the index from this loop to insert the correct title.
eg:
int count;
for (count = 0; count < [[object valueForKey:#"note title"] count]; count++)
{
// Do your other insert stuff here
[newNote setValue:[[object valueForKey:#"note title"] objectAtIndex:count] forKey:#"title"];
}
again this is just a dirty example of what you could possibly do so solve this problem.