How do I send the mutable string to the NSTextField properly? - objective-c

So I have all this code that I have debugged and it seems to be fine. I made a mutable string and for some reason I can not get it to be displayed on my label. the debugger says
"2010-04-22 22:50:26.126 Fibonacci[24836:10b] *** -[NSTextField setString:]: unrecognized selector sent to instance 0x130150"
What is wrong with this? When I just send the string to NSLog, it comes out fine.
here's all my code, any help would be appreciated. "elementNum" is a comboBox and "display" is a Label.
Thanks
#import "Controller.h"
#implementation Controller
- (IBAction)computeNumber:(id)sender {
int x = 1;
int y = 1;
NSMutableString *numbers = [[NSMutableString alloc] init];
[numbers setString:#"1, 1,"];
int num = [[elementNum objectValueOfSelectedItem]intValue];
int count = 1;
while (count<=num) {
int z = y;
y+=x;
x=z;
[numbers appendString:[NSString stringWithFormat:#" %d,", y]];
count++;
}
[display setString:numbers];
NSLog(numbers);
}
#end
`

Look at the error message you're getting:
-[NSTextField setString:]: unrecognized selector sent to instance 0x130150"
This is telling you something. Specifically, that NSTextField does not have a -setString: method and trying to call it will fail.
This is your cue to look at the docs for NSTextField. When you do so, you will see that there are no methods to set the string value. However, the docs also show you that NSTextField inherits from NSControl, which has a -setStringValue: method.
So, you need to call -setStringValue: to set the value of an NSTextField.
[display setStringValue:numbers];
Note that in your code at present, you are leaking the numbers string object. You created it using -alloc, so you are responsible for releasing it.
Instead, you should create it using [NSMutableString stringWithString:#"1, 1,"], which will return an autoreleased object, as well as initializing it in the same message.

Related

Using NSString value to refer to UILabel

Have mercy, newbie here.
I have a NSString value that I construct on the fly, which is the name of a UILabel instance. I want to send the label a message to update its text. But, the two data types don't match. Here's enough code (I think):
In header file:
IBOutlet UILabel *Clue1; // IBOutlet and IBAction are IDE flags
IBOutlet UILabel *Clue2; // IB = interface builder
IBOutlet UILabel *Clue3;
In implementation file:
- (IBAction) newPuzzle:(id)sender { // Clear all fields & get new clue
[Clue1 setText:#""]; // Clear the fields
[Clue2 setText:#""];
[Clue3 setText:#""];
// Send up a randomly chosen new clue
NSArray *clues = [NSArray arrayWithObjects:#"222", #"333", nil];
NSInteger randomIndex = arc4random()%[clues count];
NSString *aClue = [clues objectAtIndex:randomIndex];
// The clue will be split into component digits and each piece sent to a different label
for (NSInteger charIdx = 0; charIdx < aClue.length; charIdx++) {
NSString *cluePos = [NSString stringWithFormat:#"Clue%d", charIdx + 1];
NSLog(#"%#", cluePos); // works
[cluePos setText:#"test"]; // Xcode notes the type mismatch
}
}
There are some similar questions on SO, but none are close enough for me to recognize that they apply to my case, at least as far as I can tell. Using the terminology of another language (R), I need to "coerce" the class of cluePos from NSString to UILabel. I'm on Xcode 4.2.1 and OSX 10.7.2.
TIA.
You can't coerce a string into a label because they are fundamentally different. The string doesn't have any knowledge of your view controller class or it's properties (some of which happen to be labels).
You can however use the valueForKey: method to get a property of an object by name, where the name is specified as a string. So to get a property called Clue1 on my view controller I'd say:
UILabel *label = [self valueForKey:#"Clue1"];
Or in your case, this:
NSString *cluePos = [NSString stringWithFormat:#"Clue%d", charIdx + 1];
UILabel *label = [self valueForKey:cluePos];
label.text = #"test";
(I'm assuming 'self' in this case refers to the view controller, but you can call this on any object that has properties.)
Another way to do this is to turn your string into a selector using NSSelectorFromString. That would look like this:
SEL selector = NSSelectorFromString(#"Clue1");
UILabel *label = [self performSelector:selector];
For your purposes either solution works equally well, however the advantage of using the selector is that you can pass arguments to the method call (so you could call a method that returns an object, not just access a property or IBOutlet).
Note that both of these methods will raise an exception if you try to access a property or call a method that doesn't exist. You can test if the property exists before calling it by saying:
SEL selector = NSSelectorFromString(#"Clue1");
BOOL labelExists = [self respondsToSelector:selector];
if (labelExists)
{
UILabel *label = [self performSelector:selector];
label.text = #"test";
}
else
{
//do something else
}

Objective C 's NSString subStringToIndex causing strange issue

Hi everyone I am working on a game and I have run into a really weird issue and was hoping to get some help. Basically sometimes the text is a bit long to show in one textbox so I wanted it to break down a string and store the undisplayed text in a string to be used in the next message box. So when I use this code..
NSString * Talkin1 = #"Hello I am an annoying string";
NSString * Talkin2 = [Talkin1 substringToIndex:5];
It makes Talkin2 the value of Hello which is what I want. Then I store it in the object with..
[_window setMultiMessage:Talkin2];
which goes to my set and get methods in an object i made.
In it's interface...
NSString * multiMessage;
in its .m
-(void) setMultiMessage:(NSString*)messageTwo
{
multiMessage = messageTwo;
}
-(NSString*) getMultiMessage
{
return multiMessage;
}
then later the main object pulls it out again, when it is done closing the first window with...
NSString * talking = [_window getMultiMessage];
Now in debugging, I have noticed talking's value will be "out of scope" when i get the string back from _window. So then it crashes my program when it tries to use it.
But. If i do this everything works fine.
NSString * Talkin1 = #"Hello I am an annoying string";
//NSString * Talkin2 = [Talkin1 substringToIndex:5];
[_window setMultiMessage:Talkin1];
So it works perfect (except for splitting the string like I want) when I use #" " but not when I use any result of substringToIndex or substringFromIndex.
I am new to objective c so I assume it is something basic I am missing. Any help would be wonderful! Thank you in advance.
(Assuming no GC.)
-substringToIndex: returns an autoreleased object. But you are not retaining the object in the setter, thus no one "owns" the Talkin2 and it will be deallocated "later". You need to copy or retain the string in the setter.
-(void) setMultiMessage:(NSString*)messageTwo {
if (multiMessage != messageTwo) {
[multiMessage release];
multiMessage = [messageTwo retain];
}
}
Actually you should really use Objective-C 2.0's declared property feature. It allows correct setter and getter be generated automatically.
#interface .... { ... }
...
#property(copy) NSString* multiMessage; // <--
...
#end
#implementation ....
#synthesize multiMessage; // <--
...
#end
...
_window.multiMessage = Talkin2;
// or: [_window setMultiMessage:Talkin2];
NSString* talking = _window.multiMessage;
// or: talking = [_window multiMessage];

Objective-C handling integer values

I am getting confused with how to handle Integers in Objective C.
If I define the following:
NSInteger i = 6;
NSLog(#"%d", i);
I expect it to print 6 to the console.
however I have an NSInteger within an object which is obviously reference by a pointer so I get very difference results.
For example:
#interface Section : NSObject {
NSInteger Id;
}
#property (nonatomic, assign) NSInteger Id;
Please assume this has been synthesized in the implementation.
I create the object set its value and access it again as follows:
Section *section = [[Section alloc] init];
section.Id = 6;
NSMutableArray *sections = [[NSMutableArray alloc] init];
[sections addobject:section];
Section *sectionB = [setions objectAtIndex:0];
NSLog(#"%d", sectionB.Id);
This has the strange effect of printing the memory address ie a number like 5447889. Why can I not just get the value?
I have tried using:
NSInteger sid = [[section Id]integerValue];
But I then get the warning Invalid receiver type 'NSInteger' and sometime get an error Program received signal: “EXC_BAD_ACCESS”.
I would really like to know how to handle Integers, or any values for that matter properly.
Many Thanks
It looks like you're accessing uninitialized memory; 5447889 doesn't look like a pointer value—pointers are usually word-aligned, and 5447889 isn't word aligned.
Maybe you could cut and paste your actual code. This has typos such as addobject instead of addObject and setions instead of sections.
Does it work if you keep things simple and do NSLog(#"%d", section.Id) to skip messing with the array?
Regarding the strange values, see Dominic Cooney's answer.
Regarding the EXC_BAD_ACCESS: [[section Id]integerValue]; doesn't work because it then tries to interpret the NSInteger as an object and tries to send the message integerValue to it, which can't work. It's an integral number, not an object.
Think I found the answer to my own question. Setting the value of an NSInteger to a value of say 6 is fine. The problem I have is I am setting it to the value returned from a Json string using the following:
NSInteger i = [jsonResult objectForKey:#"Id"];
which should be:
NSInteger i = [[jsonResult objectForKey:#"Id"] integerValue];
I have not tested this but makes sense based on what DarkDust said about integerValue taking an object and not an Integer.
Thanks for your input.

Objective C: What is the best way to create and use a dynamic boolean array?

I have been struggling with the best way of creating, accessing and updating values from a dynamic boolean array for more than a week now.
#interface myDelegate : NSObject
{
NSMutableArray *aShowNote;
}
#property (nonatomic, copy) NSMutableArray *aShowNote;
This is how I have initialised my array:
NSMutableArray *aShow = [[NSMutableArray alloc] init];
for (i=0; i < c; i++)
[aShow addObject:[NSNumber numberWithBool:false]];
self.aShowNote = aShow;
This seems to work OK but I'm baffled why each element is initialised with the same address.
But then what I've discovered in my research so far is that is seems that you need to replace the object if you want to change its value:
myDelegate *appDelegate = (myDelegate *)[[UIApplication sharedApplication] delegate];
NSInteger recordIndex = 1;
NSNumber *myBoolNo = [appDelegate.aShowNote objectAtIndex:recordIndex];
BOOL showNote = ![myBoolNo boolValue];
[appDelegate.aShowNote replaceObjectAtIndex:recordIndex withObject:[NSNumber numberWithBool:showNote]];
but this approach just seems to be over complicated (and it crashes too).
Terminating app due to uncaught exception'NSInvalidArgumentException', reason: '-[__NSArrayI replaceObjectAtIndex:withObject:]: unrecognized selector sent to instance 0x5b51d00
Any pointers to improve this code (and of course to make it work) would be very gratefully received.
Thanks
Iphaaw
the problem is that copy in a property copies the assigned object. And copy creates immutable objects.
Change your property to read: #property (nonatomic, retain) NSMutableArray *aShowNote;
And I think there is not much to improve, from what I know this is the way to go if you want an NSArray with booleans.
Why not use plain C for this simple case?
BOOL *aShow = malloc(sizeof(BOOL)*c);
for (i=0 ; i<c ; i++)
aShow[i] = false;
You just have to remember to free(aShow) when you are done with it.
It is not possible to change value of a NSNumber. It not mutable class.
Then, when you ask for two same value, the same object is return.
In your array init, why you don't initialized directly the array to avoid copy problem:
aShowNote = [[NSMutableArray alloc] init];
for (i=0; i < c; i++) {
[aShowNote addObject:[NSNumber numberWithBool:false]];
}
I'm baffled why each element is initialised with the same address.
Why? NSNumbers are immutable. The runtime only needs one NSNumber object to represent FALSE.

Using int datatype in objective-c

First, I'm very new with objective-c and memory management, pointers, etc. No doubt my problem lies in a simple point I'm missing.
I've got a class which contains a property for an integer:
// Device.H file
#interface Device : NSObject {
#private int nodeLevel;
}
#property (readwrite, assign, nonatomic) int nodeLevel;
// Device.m file
#implementation Device
#synthesize nodeLevel;
- (id)init {
self.nodeLevel = 0;
return self;
}
I create an NSMutableArray of many Device objects, assigning the node Id:
-(NSMutableArray *)getDevices {
...
NSMutableArray *devices = [[NSMutableArray alloc] initWithCapacity:[rDevices count]];
for (NSDictionary *d in rDevices) {
Device *newDevice = [[Device alloc] init] autorelease];
newDevice.nodeLevel = d.nodeLevel;
[devices addObject: newDevice];
}
return [devices autorelease];
}
My devices array is stored on the main app delegate where I've got a property assigned to hold it:
#property (nonatomic, retain) NSMutableArray *devices;
Now here's where my problem is manifest. I'm using a tableView in another controller class to access my app delegate, pull a device from its array then set values with the int, but 'strange' things happen:
EDIT: Min/Max values for the slider are set in another part of the code to 0 and 100 respectively.
// In method cellForRowAtIndex
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
Device *d = (Device *)[[appDelegate.devices objectAtIndex:indexPath.row]];
// cell is a custom cell with a UISlider object
cell.sliderLevel.value = [d nodeLevel];
When I assign value to the device's nodeLevel, the slider is always maxed out, even if nodeLevel only equals 1 or 2.
If I do this instead, the slider is at the correct position, but I'll eventually get a "EXC_BAD_ACCESS" signal when scrolling up and down through my tableView:
// cell is a custom cell with a UISlider object
cell.sliderLevel.value = [[d nodeLevel] intValue];
I suspect that I must be assigning the value to a memory location in the first instance? In the second case it works, but I assume that my BAD_ACCESS is a result of the nodeLevel becoming "released" or something? One final note, I've also got an NSString object associated with the Device class. I access the string and assign it to a label in my cell and it never causes me problems.
Thanks in advance for taking a look.
What type is returned by the nodeLevel property in this line: "newDevice.nodeLevel = d.nodeLevel;"? The nodeLevel property in Device is an int, so you need to ensure that d.nodeLevel is returning an int, and not an NSNumber object.
If d.nodeLevel is returning an NSNumber, that would explain why calling intValue on it gets you a reasonable value, and you get a huge number if you don't call intValue on it (the huge value would be the pointer value for the NSNumber object). It would also explain why you get an EXC_BAD_ACCESS crash later on, because your NSNumber object isn't being retained.
You should probably just change this line:
newDevice.nodeLevel = d.nodeLevel;
to
newDevice.nodeLevel = [d.nodeLevel intValue];
and don't call intValue on it later on, so you would change this:
cell.sliderLevel.value = [[d nodeLevel] intValue];
to this:
cell.sliderLevel.value = [d nodeLevel];
[d nodeLevel] returns an integer, a primitive type, not an Objective-C object. Therefore, you cannot call -intValue on it, and that's why you get an EXC_BAD_ACCESS.
Further, the reason your slider is maxed out is because you haven't set its maximum value to 2.0. Because it defaults to 1.0, when you set it to any value 1.0 or higher, it will appear maxed out (in your case, both 1 and 2 appear the same). At some point, you need to call cell.sliderLevel.maximumValue = 2.0; to make the maximum value possible high enough.