Class method NSString Param turns into NSCFString

Discussion in 'iOS Programming' started by AndyCodez, Aug 6, 2009.

  1. AndyCodez macrumors regular

    Joined:
    Aug 6, 2009
    #1
    I have a method like the following called in a different class, this method sets a static NSString.

    Code:
    
    static NSString *histString;
    
    + (void) setTheString:(NSString*) str1
    {
       histString = str1;
    }
    
    
    I then proceed to set histString to an array but the program crashes because the type is NSCFString. Am I missing something major here? I'm teaching myself objective c and I have not ran across this issue in the book I have.

    Thanks for any help I have been stuck on this for 2 or 3 days.
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    NSString is a strange beast: it's toll-free bridged to CFString, and, I think it's underlying representation is a NSCFString. Nothing should be wrong with what you've posted, but where you say "I then proceed to set histString to an array" worrys me. What do you mean by this? Can you post code? You certainly can't do (for instance)

    Code:
    char[] myChars = histString;
    
    and expect it to work.
     
  3. AndyCodez thread starter macrumors regular

    Joined:
    Aug 6, 2009
    #3
    I'm at work right now, but if i remember correctly it something along these lines:

    Code:
    
    NSMutableArray *histArray;
    
    [histArray addObject:histString];
    
    
    Which I had something like [histArray addObject:mad:"Cake"]; or
    NSString *strShort = @"Cake";
    [histArray addObject:strShort];

    and those worked fine.
     
  4. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    The only thing I can suggest is to post all the code and the exact error when you can...
     
  5. AndyCodez thread starter macrumors regular

    Joined:
    Aug 6, 2009
    #5
    Ok thanks :) I'll do it while I'm on lunch. Basically it doesn't error, it will crash the program when trying to set [histArray addObject:histString]; I assumed it was because histString was of type NSCFString.

    Do you know why methods with NSString params are set to type NSCFString instead of NSString that I had specified in the method declaration?
     
  6. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #6
    If it just crashes then post what you see in the debugger.

    My understanding is that every NSString is always really a NSCFString as is every CFString. Nothing turns an NSString into a NSCFString: it was always one.
     
  7. AndyCodez thread starter macrumors regular

    Joined:
    Aug 6, 2009
    #7
    Here is the code:

    Code:
    
    @interface HistoryTableViewController : UIViewController {
    	NSMutableArray *histList;
    	
    }
    
    static NSString *historyString;
    static NSString *histStringOperator;
    static NSString *histStringVal1;
    static NSString *histStringVal2;
    
    // History methods
    + (void) setHistoryStringTotal:(NSString*) hString;
    + (void) setHistoryStringVal1:(NSString*) hString1;
    + (void) setHistoryStringVal2:(NSString*) hString2;
    + (void) setHistoryStringOperator:(NSString*) op;
    + (NSString*) retHistoryString;
    
    @end
    
    Code:
    
    
    @implementation HistoryTableViewController
    
    
    + (void) setHistoryStringTotal:(NSString*) hString
    {
    	historyString = histStringVal1;
    	historyString = [historyString stringByAppendingString:(histStringOperator)];
    	historyString = [historyString stringByAppendingString:(histStringVal2)];
    	historyString = [historyString stringByAppendingString:(hString)];
    }
    
    + (void) setHistoryStringVal1:(NSString*) hString1
    {
    	histStringVal1 = hString1;
    	
    }
    
    + (void) setHistoryStringVal2:(NSString*) hString2
    {
    
    	histStringVal2 = hString2;
    }
    + (void) setHistoryStringOperator:(NSString*) op
    {
    	
    	histStringOperator = op;
    	
    }
    
    + (NSString*) retHistoryString
    {
    	return historyString;
    }
    
    // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
    - (void)viewDidLoad {
        [super viewDidLoad];
    	
    	histList = [[NSMutableArray alloc] init];
    	
    	[histList addObject:historyString];
    	[histList addObject:@"Pie"];
    	
    	self.navigationItem.title = @"Calculation History";
    }
    
    
    Shorter section of implementation of a different class, with out the .h
    Code:
    
    	switch(operation)
    	{
    		case 1:
    			value = value + [Globals doubleVal];
    			//DisplayText = [NSString stringWithFormat:@"%d", value];
    			break;
    		case 2:
    			value = [Globals doubleVal] - value;
    			//DisplayText = [NSString stringWithFormat:@"%d", value];
    			break;
    		case 3:
    			value = ([Globals doubleVal]/value);
    			//DisplayText = [NSString stringWithFormat:@"%d", value];
    			break;
    		case 4:
    			value = value * [Globals doubleVal];
    			//DisplayText = [NSString stringWithFormat:@"%d", value];
    			break;
    		default:
    			DisplayText = @"";
    	}
    	
    	[HistoryTableViewController setHistoryStringVal2:txtOutput.text];
    	DisplayText = [Globals convertToString:(value)];
    	[HistoryTableViewController setHistoryStringTotal:DisplayText];
    	txtOutput.text = DisplayText;
    	
    	[Globals setHistString:(DisplayText)];
    
    	storedNum = 0;
    		
    }
    
    //Operation =  1 = add, 2 = subract, 3 = divide, 4 = multiply
    - (IBAction) btnAddPress:(id) sender
    {
    	//Store the first number
    	[Globals setVal:([txtOutput.text floatValue])];
    	[HistoryTableViewController setHistoryStringVal1:(txtOutput.text)];
    	[HistoryTableViewController setHistoryStringOperator:@" + "];
    		
    	//clear out the textbox
    	txtOutput.text = @"";
    	
    	//Set the operation for when the user hits enter
    	operation = 1;
    }
    
    - (IBAction) btnSubtractPress:(id) sender
    {
    	[Globals setVal:([txtOutput.text floatValue])];
    	[HistoryTableViewController setHistoryStringVal1:(txtOutput.text)];
    	[HistoryTableViewController setHistoryStringOperator:@" - "];
    	
    	//clear out the textbox
    	txtOutput.text = @"";
    	
    	//Set the operation for when the user hits enter
    	operation = 2;
    }
    
    - (IBAction) btnDividePress:(id) sender
    {
    	[Globals setVal:([txtOutput.text floatValue])];
    	[HistoryTableViewController setHistoryStringVal1:(txtOutput.text)];
    	[HistoryTableViewController setHistoryStringOperator:@" / "];
    	
    	//clear out the textbox
    	txtOutput.text = @"";
    	
    	//Set the operation for when the user hits enter
    	operation = 3;
    }
    
    - (IBAction) btnMultiplyPress:(id) sender
    {
    	[Globals setVal:([txtOutput.text floatValue])];
    	[HistoryTableViewController setHistoryStringVal1:(txtOutput.text)];
    	[HistoryTableViewController setHistoryStringOperator:@" X "];
    	
    	//clear out the textbox
    	txtOutput.text = @"";
    	
    	//Set the operation for when the user hits enter
    	operation = 4;
    }
    
    When it crashes it says that histStringVal1 variable is invalid when I scroll over it to see what the value is while debugging. I'm not sure why it would be erroring I was thinking that its because of where the static methods are declared outside of the interface of the class, but you cant have variables in class methods that are in the interface for some reason... I get an error when I try to do that. I'll post more when I get back to work :) Thanks!
     
  8. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #8
    A setter whose parameter is an object has to retain that object.

    You're not retaining the strings in several places in your code and they are being autoreleased so they become invalid.
     
  9. AndyCodez thread starter macrumors regular

    Joined:
    Aug 6, 2009
    #9
    So basically i should be using [theString retain]; after i use it when its being called from a different class, in the setter of the static variable? I'm just learning all of this memory management stuff, never really had to worry about it before. I know i wouldn't need to do that with a type such as an Int, correct?

    It seems there is a steep learning curve on objective C. At work I use Visual FoxPro (old school lol), and use a software from a company called HighJump for warehouse management development. Yes its terrible and old as well.

    Having a good time learning objective c and the iphone SDK, except when i run into issues like this where I'm stuck for a few days!
     
  10. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #10
    Since we have entered the days of the @property writing a correct setter seems to be a lost art.

    I can't see from what you posted why your methods are class methods. If it's possible to make them instance methods then do that. Then use @property to make your setters and getters. This will make your code more likely to be correct.
     
  11. AndyCodez thread starter macrumors regular

    Joined:
    Aug 6, 2009
    #11
    Well i assumed the + (void) ect is what makes it a class method vs - makes it an instance method.
     
  12. AndyCodez thread starter macrumors regular

    Joined:
    Aug 6, 2009
    #12
    Yep that was the problem I needed to have [theString retain]; in the setter. I didn't realize that those variables would be released every time the application leaves the scope.

    Thanks phoney that really helped and I'll make sure to remember that!
     

Share This Page