views:

65

answers:

2

Hi guys,

I'm a newbie on the iphone development world..

I started a new project, I used it to test what I learned about objective c, it basically sends and recives data from my local server, then, I store some of that data inside the class, it works fine. Everything is on the command line.

my class definition:

@interface MyClient : NSObject {

    NSString *name;

    NSMutableDictionary *in, *out;
}
-(BOOL) send;
-(BOOL) receive;

I set up the "out" values, convert them to xml and send them to my server. my server responds, i get the "in" values the name is a string that contains some special value of the "in" values.

The problem comes when I try to mix my code with some example/demo I found on internet, the demo brings some MVC?? files (*Handler.h/m , *ViewController.h/m, *AppDelegate.h/m). There is one button (btnStart), if I press that button it calls

- (IBAction) start: (id) sender;

everything works fine if I put the send and receive calls inside the start method.

BUT...

I tried two have to buttons: send and receive, both works (I have tried them and sending output to the console), both methods are:

 1) - (IBAction) send: (id) sender;
 2) - (IBAction) receive: (id) sender;

both inside *Handler.m

then: method 1) will just perform [myClient send]; method 2) will just perform [myClient receive];

it does not work, it throws me a "BAD_ACCESS" error, I debugged (I used NSZombie..) ...

I found that the data which is stored (in, out, name) when is called [myClient send] is released/killed/does not exist when calling [myClient receive]

I have not called [myClient release] or something like that.

questions: what am i doing wrong? where should that code (method 1) and 2) ) be?

thanks.

UPDATED: Here is some code, it's huge, so I have copy & pasted the significative part, let me know if you need more code, thanks!

// MyClass.h

@interface MyClient : NSObject {

    NSString *name;
    NSString *id;

    NSMutableDictionary *paramIn, *paramOut;
}
-(BOOL) send;
-(BOOL) receive;
-(void) setParam:(NSString *) key value: (NSString *) value;
-(NSString *) getParam:(NSString *) key;

//MyClass.m
#import "MyClass.h"
#import "TBXML.h"

@implementation MyClass
-(id) init {
    if ( !(self= [super init]) ){
        return nil;
    }

    paramIn=[[NSMutableDictionary alloc] init] ;
    paramOut=[[NSMutableDictionary alloc] init] ;

    return self;
} 

-(void) setParam:(NSString *) key value: (NSString *) value {
    [paramOut setObject:value   forKey:key];
}
-(NSString *) getParam:(NSString *) key {
    return [paramIn objectForKey:key];
}
-(BOOL) send{
    NSString *xml=[self getXML];
    // url conection ...
    // NSURLReq ...
    NSData *data= [ buffer  dataUsingEncoding: NSASCIIStringEncoding];
    TBXML * tbxml = [[TBXML tbxmlWithXMLData: data] retain];

    BOOL r=[self getXML: tbxml usingThisDictionary: &paramIn];

    if (r == YES) {
        name = [self getParam:@"nameResponse"];
        id =[self getParam:@"myId"];
    }
    [xml release];
    [data release];
    [tbxml release];

    return r;
}
-(BOOL) getXML:(TBXMLElement *)element usingThisDictionary:(NSMutableDictionary **) map {
    // search for each element...
    if (someError) return NO;

    [*map setObject: [TBXML attributeValue:attribute] forKey:[TBXML elementName:element]];

    return YES;
}
@end

UPDATED: Thanks guys (IwasRobbed, Simon, TechZen)

I have been debugging and changing code...I found that: in order to mantain the name name and id value, I have to do:

name =[[self getParam:@"nameResponse"] copy];
id =[[self getParam:@"myId"] copy];

questions: Q1. talking about the old code (whitout the copy), the name and id value is released because

1) it's tailed to the paramIn dictionay, and paramId is released?

OR

2) both values are copied from paramIn dictionay, but there is no retain/copy instruction

I thought, the answer is 2), right?

Q2. how may I retain the values stored in the NSMutableDictionaries paramIn and paramOut ?

thanks

+1  A: 

If you didn't alloc or retain the object in question (the string?), and is given to you by another method, it is probably autoreleased. From what I understand, the object is only kept around until the autorelease pool is released (at the end of the current run loop?). This will cause calling send: and receive: in the same loop work (when calling them in the same function), but when called separately, will cause an error, since the object has been autoreleased.

Simon
Yes, I have been debugging and changing code...I found tha:in order to mantain the name name and id value, I have to do: name =[[self getParam:@"nameResponse"] copy]; id =[[self getParam:@"myId"] copy];
jhon
+1  A: 

Your instance variables name, in and out are not defined as properties so you have to micromanage their retention. If you did not, then they will not survive long beyond the scope of the method where you set them.

The simplest solution is to make properties for the instance variables thusly:

@property(nonatomic, retain)  NSString *name;
@property(nonatomic, retain)  NSMutableDictionary *in;
@property(nonatomic, retain)  NSMutableDictionary *out;

... and then use the self notation e.g. self.name to access them.

TechZen
correct me if i'm wrong, but, defining them as properties will make them availables from outside the class, i.e:MyClass example= [[MyClass alloc] init ];NSString *name= example.name;if that is the case, then i should retain them "somewhere else", right?
jhon
They're visible outside the class anyway unless you mark them as private regardless of whether or where you define the properties. Properties are really just synthesized methods. They don't affect visibility. You have to manage the retention of iVars one way or the other. You either use the @property directive, you write the accessors manually or you make the mistake of handling retention on the fly throughout the class' code. I recommend the former.
TechZen