I'm running into problems with a selector. I'm trying to dynamically name an array, winnerArray1, winnerArray2, winnerArray3, etc.
The variable someVariable is in a loop that increases so that will get incremented.
I get unrecognized selector sent to instance
int someVariable = 1;
NSArray *winnerArray;
NSString *tempLoopString;
while(someVariable < 4){
tempLoopString = [NSString stringWithFormat:#"winnerArray%d", someVariable];
SEL selector = NSSelectorFromString(tempLoopString);
winnerArray = [self performSelector:selector];
if ([winnerArray do_stuff]) {
do stuff here
}
someVariable++
}
You can't refer to a variable by name like that.
You should look into using key value coding. With that, you can interrogate a property of some object using the method valueForKey:
Related
I have created an NSArray from a text file with
void arrayfromfile {
// get a reference to our file
NSString *myPath = [[NSBundle mainBundle]pathForResource:#"CalendarQuotes" ofType:#"txt"];
// read the contents into a string
NSString *myFile = [[NSString alloc]initWithContentsOfFile:myPath encoding:NSUTF8StringEncoding error:nil];
// split our string into an array
NSArray *mySplit = [myFile componentsSeparatedByString:#"\n"];}
Now what I'd like to do is set label.text to mySplit[x] while x< mysplit.count and call it every time a user swipes up.
setlabeltextmethod quote {
if x<mySplit.count {
label.text = mySplit objectatindex x
x+=1
else { label.text = #"thats it folks" }
}
What I'm having trouble with is accessing mySplit from the quote so I can manipulate it to give me the quote at index x.
When I tried to access it from my swipe method:
- (IBAction)swipeUp:(id)sender {
[self doAnimationUp];
NSLog (#"swipedUp");
NSLog(#"array%#" , [mySplit objectAtIndex:0]);
NSLog(#"arraycreated");
//I'm using NSLog for debug purposes but this is where I would setlabeltext.text to mySplit objectAtIndex
}
I get array[null].
Your mySplit variable is local to arrayfromfile, so once that method returns the variable has gone. There is more than one approach to solving this. One is making it an instance variable, that is a variable that belongs to your current class instance and is visible to every instance method. Start you implementation like this:
#implementation MyClassName
{
NSArray *mySplit;
}
Now set the variable in the instance method arrayfromfile and read it in the instance method swipeUp - both calls must be made in the same instance of your class, each instance has its own set of instance variables.
Other options include adding a property to the class or, if you must, a global variable of some kind.
HTH
I am getting this error when trying to add the NSString object named object to my array :
erminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI addObject:]: unrecognized selector sent to instance 0x7fc48ae52ba0'
Not sure why this is so. I was originally using NSArray to changed it to NSMutableArray but I am still having problems with it. Code is below:
-(NSMutableArray *)getReplyArrayForMessage: (NSString *)message {
//get the array
NSMutableArray *replies = [self.messageDictionary objectForKey:message];
NSLog(#"%#",replies);
//if no replies we init the base set
if([replies count]==0) {
//get the base array
//this also works if a key just isn't in the dictonary
return replies=[self getBaseArray];
}
else {
//add the other message
NSString *object = #"Send a different message";
[replies addObject:object];
return replies;
}
}
If anyone could give me a pointer to why this is happening I would appreciate it. Noob here.
The array is immutable (NSArray), not mutable (NSMutableArray). You can create a mutable array from an immutable array using mutableCopy:
NSMutableArray *replies = [[self.messageDictionary objectForKey:message] mutableCopy];
I know this from the exception text:
-[__NSArrayI addObject:]: unrecognized selector sent to instance ...
^^^^^^^^^^
EDIT I've missed off some important information from my original answer.
Having used mutableCopy you now have a copy of the array and the original array (from self.messageDictionary objectForKey:message) will remain unchanged after you add your element. This is almost certainly not what you intended.
As I've mentioned in the comments below, you probably want to create a custom object to hold these details (or an array of custom objects) that should be created from the message dictionary as soon as you receive it. The effort required to create a custom object will pay for itself tenfold in the long term.
You are trying to add an NSString to an NSArray (which looks like an NSMutableArray) since you initialized it as one. This means that the object that you store in your messageDictionary is actually of type NSArray, and not NSMutabelArray. So, assigning it to an object of type NSMutableArray won't actually change its type and make it mutable.
It's an easy fix:
NSMutableArray *replies = [[NSMutableArray alloc] initWithArray:(NSArray *) [self.messageDictionary objectForKey:message]];
Or you can go with mutableCopy (as suggested by #trojanfoe) which is a shortcut but will lead to the same result.
I can tell because the error message says -[__NSArrayI addObject:]: unrecognized selector sent to instance 0x7fc48ae52ba0'. Notice the I at the end of __NSArrayI, this means that this array is actually immutable, so you can't add objects to it.
I have an NSArray made of UILabels that I initialized with this statement (the actual pointer is created in the .h file):
interLabels = [NSArray arrayWithObjects:inter1,inter2,inter3, nil];
Later on I have an IBAction method that responds and is supposed to update the array of labels when a button is clicked:
-(IBAction)intervalButton:(id)sender{
int count = 0;
double val[3];
if(count < 3){
val[count] = number;
[interLabels objectAtIndex:count].text = [NSString stringWithFormat:#"%.2f", val[count]];
count++;
}
}
However, [interLabels objectAtIndex:count] doesn't seem to be recognized as a UILabel object, so I get a compiler error that states that the property "text" cannot be found on object type "id." How can I get the compiler to recognize this as a UILabel? Is this an issue that can be solved by typecasting?
objectAtIndex returns you an reference of type 'id'. You need to cast it to UILabel before the compiler / IDE will recognise the text property.
E.g.
((UILabel*) [interLabels objectAtIndex:count]).text = ...
Type id does not need to be casted if you assign it to another variable. And in your case i think it would be nicer since you actually do two things, first get a object from the array and then changes state on that object. Consider this.
-(IBAction)intervalButton:(id)sender
{
for ( UILabel *label in interLabels )
{
label.text = [NSString stringWithFormat:#"%.2f", number];
}
}
I assumed you wanted a loop not a if statement since the if statement always evaluated to YES. Also i assumed number is a instance variable in your class.
Actually when i looked at the code again you can probably remove most of it.
I use core data to store some arrays as strings. The strings are prefixed with STRINGFROMARRAY and delimited by &,&.
I thought it would be neat to override the setters and getters so I wouldn't have to provide code to convert them every time I needed access. I have created a managed object subclass called TestEntity with only one attribute, "memberIds" (string). I have verified that my custom setter and getter seem to work fine:
TestEntity.h:
#interface TestEntity (CoreDataGeneratedAccessors)
- (NSArray*)memberIds;
- (void)setMemberIds:(NSArray *)memberIds;
#end
TestEntity.m:
#implementation TestEntity
#dynamic memberIds;
- (NSArray *)memberIds
{
[self willAccessValueForKey:#"memberIds"];
NSArray *memberIdsArray = [NSArray arrayWithArray:[[[self primitiveValueForKey:#"memberIds"] substringFromIndex:15] componentsSeparatedByString:#"&,&"]];
[self didAccessValueForKey:#"memberIds"];
return memberIdsArray;
}
- (void)setMemberIds:(NSArray *)memberIds
{
NSString *stringFromArray = [#"STRINGFROMARRAY" stringByAppendingString:[memberIds componentsJoinedByString:#"&,&"]];
[self willChangeValueForKey:#"memberIds"];
[self setPrimitiveValue:stringFromArray forKey:#"memberIds"];
[self didChangeValueForKey:#"memberIds"];
}
#end
I can set an array value and it properly stores as a string. I can also use valueForKey to log the value after it's set, and it properly prints as an array.
However, when I attempt to log the entire managed object (without valueForKey:), I get a [NSArray length] unrecognized selector error.
Here's the code I'm using to test this:
NSManagedObject *test = [NSEntityDescription insertNewObjectForEntityForName:#"TestEntity" inManagedObjectContext:[SyncEngine sharedEngine].managedObjectContext];
[test setValue:[NSArray arrayWithObjects:#"1", #"2", #"3", nil] forKey:#"memberIds"];
NSLog(#"%#", [test valueForKey:#"memberIds"]);
NSLog(#"%#", test);
And here's the output:
2013-08-24 13:59:27.820 0.1[1440:19d03] (
1,
2,
3
)
2013-08-24 13:59:27.820 0.1[1440:19d03] -[__NSArrayI length]: unrecognized selector sent to instance 0xa533800
Why is the length message getting sent to my array? And how can I prevent this crash? Thanks!
I think the problem is that you have overriden memberIds methods.
In your model, memberIds should return a string, and you've overriden it to return an NSArray.
So, when your managedobjet is trying to generate its description, it is assuming that memberIds is a string.
I think the best way to do that it to name your custom getter / setter differently than your model attribute.
I have a subclass of NSManagedObject with a few "integer 32" attributes that are really enums. These enums are defined in my model's .h file like this:
typedef enum {
AMOwningCompanyACME,
AMOwningCompanyABC,
AMOwningCompanyOther
} AMOwningCompany;
I need to show a table view that displays the value of each attribute of this custom object, so for each enum I have a method that looks like this to return string values:
-(NSArray*)stringsForAMOwningCompany
{
return [NSArray arrayWithObjects:#"ACME Co.", #"ABC Co.", #"Other", nil];
}
In my table view, I iterate through the attributes of my NSManagedObject (using NSEntityDescription's attributesByName and for each attribute I call a helper method that calls the appropriate "stringsFor" method to return the strings for that particular attribute:
-(NSArray*)getStringsArrayForAttribute:(NSString*)attributeName
{
SEL methodSelector = NSSelectorFromString([self methodNameForAttributeNamed:attributeName]);
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:[[AMProperty class] instanceMethodSignatureForSelector:methodSelector]];
[invocation setSelector:methodSelector];
[invocation setTarget:self.editingPole];
[invocation invoke];
NSArray* returnValue = nil;
[invocation getReturnValue:&returnValue];
return returnValue;
}
My table view's cellForRowAtIndexPath looks like this:
...
NSString* itemName = self.tableData[indexPath.row];
NSAttributeDescription* desc = itemAttributes[itemName];
NSString* cellIdentifier = [self cellIdentifierForAttribute:desc]; // checks the attribute type and returns a different custom cell identifier accordingly
if ([cellIdentifier isEqualToString:#"enumCell"])
{
// dequeue cell, customize it
UITableViewCell* enumCell = ...
...
NSArray* stringValues = [[NSArray alloc] initWithArray:[self getStringArrayForAttribute:itemName]];
int currentValue = [(NSNumber*)[self.editingPole valueForKey:itemName] intValue];
enumCell.detailTextLabel.text = (NSString*)stringValues[currentValue];
return enumCell;
}
...
For only one of the attributes, I keep getting a crash on the NSInvocation's return array:
-[__NSArrayI release]: message sent to deallocated instance 0x856a4b0
Using the Zombies Profiler, I see:
I am using ARC. How can I debug this further?
I ran into a very similar problem myself recently and it took me a while to figure out what I was doing wrong. An extra release is being issued here -- because your pointer returnValue is __strong (the default), ARC believes that the object is owned via that pointer, but that's not the case.
-[NSInvocation getReturnValue:] doesn't take ownership of it, and the "assignment" via the pointer's address bypasses the objc_storeStrong() that ARC would normally use.
The solution is simple: mark the pointer as __unsafe_unretained. This is the truth; the object is not retained via this pointer (as it would if it were __strong), and ARC must not release it here.