简体   繁体   中英

iOS: EXC_BAD_ACCESS Error NSString length and setHTTPBody

When I start the simulator and the application starts and I click on the UI I get EXC_BAD_ACCESS for NSString *strLength = [NSString stringWithFormat:@"%d", [postStr length]]; and for [req setHTTPBody:[_postStr dataUsingEncoding:NSUTF8StringEncoding . I dont know why this happens. If I uninstall the app but keep the simulator open and run it again I get no errors. Any help would be great. Code is below.

#import "LocavoreRetroAPIAdapter.h"
//Class extention declares a method that is private to the class
@interface LocavoreRetroAPIAdapter ()
-(NSMutableURLRequest *)initRequest:(NSURL *)url method:(NSString *)method;
@end

@implementation LocavoreRetroAPIAdapter

//Called when this class is first initialized
-(id) initWithName:(NSString *)postStr webService:(NSString *)webService spinner:        (UIActivityIndicatorView *)spinner{
    if(self = [super init]){
        _postStr = postStr;
        _baseURL = @"http://base/api/";
        _webService = webService;
        _spinner = spinner;
        _result = nil;
    }
    return self;
}

//Request to Locavore API restful web services
-(void) conn:(NSString *)method{

    dispatch_queue_t concurrentQueue =     dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(concurrentQueue, ^{
        __block NSDictionary *resultBlock = nil;
        dispatch_sync(concurrentQueue, ^{
            /* Download the json here */

            //Create webservice address
            NSString *webService = [_baseURL stringByAppendingString:_webService];

            //Create the url
            NSURL *url = [NSURL URLWithString:webService];

            //Create error object
            NSError *downloadError = nil;

            //Create the request
            NSMutableURLRequest *req = [self initRequest:url method:method];

            if(req != nil){
                //Request the json data from the server
                NSData *jsonData = [NSURLConnection
                                        sendSynchronousRequest:req
                                        returningResponse:nil
                                        error:&downloadError];
                NSError *error = nil;
                id jsonObject = nil;

                if(jsonData !=nil){

                    /* Now try to deserialize the JSON object into a dictionary */
                    jsonObject = [NSJSONSerialization
                                     JSONObjectWithData:jsonData
                                     options:NSJSONReadingAllowFragments
                                     error:&error];
                }


            //Handel the deserialized object data
            if (jsonObject != nil && error == nil){
                NSLog(@"Successfully deserialized...");
                if ([jsonObject isKindOfClass:[NSDictionary class]]){
                    resultBlock = (NSDictionary *)jsonObject;
                    //NSLog(@"Deserialized JSON Dictionary = %@", resultBlock);
                }
                else if ([jsonObject isKindOfClass:[NSArray class]]){
                    NSArray *deserializedArray = (NSArray *)jsonObject;
                    NSLog(@"Deserialized JSON Array = %@", deserializedArray);
                } else {
                    /* Some other object was returned. We don't know how to deal
                     with this situation, as the deserializer returns only dictionaries
                     or arrays */
                }
            }
            else if (error != nil){
                NSLog(@"An error happened while deserializing the JSON data.");
            }else{
                NSLog(@"No data could get downloaded from the URL.");
                [self conn:method];
            }
        }
    });
    dispatch_sync(dispatch_get_main_queue(), ^{

        /* Check if the resultBlock is not nil*/
        if(resultBlock != nil){
            /*Set the value of result. This will notify the observer*/
            [self setResult:resultBlock];
            [_spinner stopAnimating];
            }
        });
    });
}

//Configure the request for a post/get method
- (NSMutableURLRequest *)initRequest:(NSURL *)url method:(NSString *)method{

    //Create the request
    NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];

    //Get the string length
    NSString *strLength = [NSString stringWithFormat:@"%d", [_postStr length]];

    //Specific to requests that use method post/get
    //Configure the request
    if([method isEqualToString:@"POST"]){
       [req addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-    Type"];
        [req addValue:strLength forHTTPHeaderField:@"Content-Length"];
        [req setHTTPMethod:@"POST"];
    }else if([method isEqualToString:@"GET"]){
        [req addValue:@"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
        [req addValue:strLength forHTTPHeaderField:@"Content-Length"];
        [req setHTTPMethod:@"GET"];
    }else{
        return nil;
    }

    //Set the HTTP Body
    [req setHTTPBody:[_postStr dataUsingEncoding:NSUTF8StringEncoding]];

    //Return the request
    return req;
}

//Called when this object is destroyed
- (void)dealloc {
    NSLog(@"DEALLOC LocavoreRetroAPIAdapter");
    [super dealloc];
    [_baseURL release];
    [_result release];
}

@end

Familiarize yourself the with memory management and object lifetime rules . Your code is crashing because you do not retain (or copy) the arguments within your init... method, and they are being deallocated. Change your init... method to:

-(id) initWithName:(NSString *)postStr webService:(NSString *)webService spinner:        (UIActivityIndicatorView *)spinner{
    if(self = [super init]){
        _postStr = [postStr copy];
        _baseURL = @"http://base/api/";
        _webService = [webService copy];
        _spinner = [spinner retain];
    }
    return self;
}

Be sure to release the three instance variables you are now copying or retaining in your dealloc method. Also call [super dealloc] as the last step in that method but that's not the source of your problem right now.

//Called when this object is destroyed
- (void)dealloc {
    NSLog(@"DEALLOC LocavoreRetroAPIAdapter");
    [_postStr release];
    [_webService release];
    [_spinner release];
    [_result release];
    [super dealloc];
}

Notice I removed the call to [_baseURL release] from your dealloc as you did not retain it so you do not own the object. If you didn't create an object with alloc or new , and didn't call retain or copy on it, then you don't own the object, so you must not release it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM