Error in Obj-C "unrecognized selector sent to instance" - iphone

Some information:
I have two different classes, "House" and "Treasury".
They are both inside the same NSMutableArray called "structures".
House has a (int) variable called "ownership".
I use a for loop (100 loops) to create houses and treasuries across an area.
Then I have another loop that loops through "structures" and assigns an "ownership" integer to it.
In that loop I use for(Houses *h in structures) but for some reason the loop also loops through the "treasury"s in structures as well.
Treasury has no ownership variable though and so I get that error telling me that "setOwnership:" does not exist.
I am also using Cocos2D but that shouldn't matter.
Here is what the code looks like:
// Variable
NSMutableArray *structures;
-(void) InitializeStructures
{
structures = [[NSMutableArray alloc]init];
for(int i = 0; i < initialColonies; i++)
{
House *h = [[House alloc]initWithFile:#"House.png"];
h.position = [self ReturnPositionOnMap]; // Returns a point in playing area
Treasury *t = [[Treasury alloc]initWithFile:#"Treasury.png"];
t.position = [self ReturnFarPointNearOrigin:h.position];
[structures addObject:h];
[self addChild:h z:1];
[structures addObject:t];
[self addChild:t z:1];
}
}
-(void) AssignOwnerships
{
for(House *h in structures)
{
// Simplified to only show where the error occurs.
h.ownership = [self ReturnID]; // Error occurs here.
// The error ONLY occurs when it is iterating through a Treasury.
}
}
Structure:
#import "CCSprite.h"
#import "ImportedGoods.h"
#interface Structure : CCSprite
{
int _integrity;
int _ID;
bool _occupied;
int _occupiedTimeLeft;
int _occupiedTimeMax;
Faction _faction;
}
#property(nonatomic, assign) int integrity;
#property(nonatomic, assign) int ID;
#property(nonatomic, assign) bool occupied;
#property(nonatomic, assign) int occupiedTimeLeft;
#property(nonatomic, assign) int occupiedTimeMax;
#property(nonatomic, assign) Faction faction;
#end
#import "Structure.h"
#implementation Structure
#synthesize integrity = _integrity;
#synthesize ID = _ID;
#synthesize occupied = _occupied;
#synthesize occupiedTimeLeft = _occupiedTimeLeft;
#synthesize occupiedTimeMax = _occupiedTimeMax;
#synthesize faction = _faction;
#end
House:
#import "Structure.h"
#import "ImportedGoods.h"
#interface House : Structure
{
int _ownership;
}
#property(nonatomic, assign) int ownership;
#end
#import "House.h"
#implementation House
#synthesize ownership = _ownership;
#end
Treasury:
#import "Structure.h"
#interface Treasury : Structure
{
int _storedWood;
int _storedWater;
int _storedStone;
int _storedFood;
}
#property(nonatomic, assign) int storedWood;
#property(nonatomic, assign) int storedWater;
#property(nonatomic, assign) int storedStone;
#property(nonatomic, assign) int storedFood;
#end
#import "Treasury.h"
#implementation Treasury
#synthesize storedFood = _storedFood;
#synthesize storedWood = _storedWood;
#synthesize storedStone = _storedStone;
#synthesize storedWater = _storedWater;
#end
This is the error:
2011-11-07 18:45:29.016 Virtual World[788:10a03] -[Treasury setOwnership:]: unrecognized selector sent to instance 0x7498cc0
2011-11-07 18:45:29.022 Virtual World[788:10a03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Treasury setOwnership:]: unrecognized selector sent to instance 0x7498cc0'
*** First throw call stack:
(0x17fb052 0x198cd0a 0x17fcced 0x1761f00 0x1761ce2 0xcbe33 0xc2193 0xc1e5f 0xc1a34 0x3fc81 0xc185e 0x176151d 0x1761437 0x39b25 0x36ee2 0x17fcec9 0x91f91 0x92adf 0x94991 0x869a30 0x869c56 0x850384 0x843aa9 0x27affa9 0x17cf1c5 0x1734022 0x173290a 0x1731db4 0x1731ccb 0x27ae879 0x27ae93e 0x841a9b 0xc07ef 0x20c5 0x1)
terminate called throwing an exception(gdb)
I know that I can just make a different NSMutableArray called "treasuries" but I'd like to keep everything in one array if possible.
I want to know why it still iterates through treasuries even though I specified to iterate through "House *h in structures".
If you need any additional information comment below and I will add.
Thanks!

When you use fast enumeration in Objective-C, which is the syntax:
for (MyClass *item in someArray) {
...
}
What you're doing is looping over every item in the array, treating each item as a pointer to a MyClass object, whether that's what the item actually is or not. It does not do what you think it does, which is only iterate over the items in the array that are of the type you declare in your loop.
What you should probably do is store your House and Treasury items in separate arrays. Do you have a specific reason for putting them in the same structure?
If you really want to store them together, you can use:
for (id item in structures) {
if ([item isKindOfClass:[House class]]) {
House *house = (House *) item;
[house setOwnership:...];
} else {
continue;
}
}

Your assumption that
for(House *h in structures)
{
// Simplified to only show where the error occurs.
h.ownership = [self ReturnID]; // Error occurs here.
// The error ONLY occurs when it is iterating through a Treasury.
}
will only pick the House objects from the array is wrong. You will get every object from the array. House *h in structures tells the compiler that array is full of House objects.
You should change it to
for (id h in structures){
// Simplified to only show where the error occurs.
if ([h respondsToSelector:#selector(setOwnership:)]){
h.ownership = [self ReturnID];
}
}

Related

Making an Integer Array in Objective-C

I want to have an internal int array for my class, but I can't seem to get XCode to let me. The array size needs to be set on initialization so I can't put the size directly into the interface.
At the moment I've been trying:
#interface TestClass : NSObject {
int test[];
}
But it tells me that I'm not allowed. How to I refer to it in my interface, and then how do I allocate it when I create the implementation?
Sorry for a somewhat standard sounding question, but I can't seem to find the answer I need from searching.
edit: I want to use an array because it's apparently much faster than using an NSArray
You can use a number of methods to overcome this problem, but the easiest is to simply make the instance variable a pointer, like this:
#interface TestClass : NSObject {
int *test;
}
#property int *test;
#end
Synthesizing the property will give it getter and setter methods which you can use to set its contents:
#implementation TestClass
#synthesize test;
//contents of class
#end
You can then use it like this:
TestClass *pointerTest = [[TestClass alloc] init];
int *array = (int *)malloc(sizeof(int) * count);
//set values
[pointerTest setTest:array];
[pointerTest doSomething];
However, using objects like NSNumber in an NSArray is a better way to go, perhaps you could do something like this:
#interface TestClass : NSObject {
NSArray *objectArray;
}
#property (nonatomic, strong) NSArray *objectArray;
#end
#implementation TestClass
#synthesize objectArray;
//contents of class
#end
You can then set its contents with a pointer to an NSArray object:
NSArray *items = [NSArray arrayWithObjects:[NSNumber numberWithInt:1], [NSNumber numberWithInt:2], nil];
TestClass *arrayClass = [[TestClass alloc] init];
[arrayClass setItems:items];
[arrayClass doSomething];
When retaining objects upon setting them (like the previous example), always make sure you deallocate the object in the classes dealloc method.
A C array is just a sufficiently sized raw memory buffer. Foundation has a nice wrapper around raw memory that frees you from all the manual memory management: NSMutableData
The following approach gives you automatic memory management plus proper encapsulation.
#interface TestClass : NSObject
#property (nonatomic, readonly) int *testArray;
#property (nonatomic, readonly) NSUInteger testArraySize;
#end
#implementation TestClass
{
NSMutableData *_testData;
}
- (id)initWithSize:(NSUInteger)size
{
self = [self init];
if (self != nil) {
_testData = [NSMutableData dataWithLength:size];
}
}
- (int *)testArray
{
return [_testData mutableBytes];
}
- (NSUInteger)testArraySize
{
return [_testData length];
}
#end
As you see, the ivar does not have to be declared in the #interface.
Try something like this:
#interface TestClass : NSObject
{
int *_test;
}
#property (assign) int *test;
#end
#implementation TestClass
- (instancetype)init
{
if (self = [super init])
{
_test = malloc(sizeof(int) * 20);
}
return self;
}
- (int *)test
{
return _test;
}
- (void)setTest:(int*)test
{
memcpy(&_test, &test, sizeof(_test));
}
- (void)dealloc
{
free(_test);
}
#end

How to retain objects in NSMutableArray IOS5

I have an array of custom objects called array which stores a bunch of core data. I use this array to populate my UITableView and to create the cells. I then try to use the same array when UISearch is opened but at this point the array is empty, how could I retain the objects in the array?
EDIT
Ok, here is some of my code
my .h file
#interface SelectCourses : UIViewController <DataHandlerDelegate, UITableViewDataSource, UITableViewDelegate, UITableViewDataSource> {
DataHandler *dataHandler;
NSMutableArray *courses;
IBOutlet UITableView *table;
IBOutlet UISearchBar *searchFilter;
//NSMutableArray *filteredCourses;
BOOL isFiltered;
}
#property (retain) NSMutableArray* filteredCourses;
Then my .m file, I have left out several functions which I believe are irrelevant
#implementation SelectCourses
#synthesize Delegate;
#synthesize filteredCourses;
...
...
- (void) dataHandlerHasLoadedCourseData:(NSMutableArray *)courseData {
courses = courseData;
[table reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(isFiltered){
return filteredCourses.count;
}
if (courses) {
NSLog(#"Count: %i", [courses count]);
if (courses.count == 1) {
return 0;
}
return [courses count];
}
else
return 0;
}
...
...
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchFiltert {
NSLog(#"searchBarSearchButtonClicked");//More debugging
if(searchFilter.text.length == 0)
{
isFiltered = FALSE;
}
else
{
NSLog(#"%#", [NSString stringWithFormat:searchFilter.text]);
isFiltered = true;
for (Course *course in courses)
{
NSRange codeRange = [course.Code rangeOfString:searchFilter.text options:NSCaseInsensitiveSearch];
NSRange nameRange = [course.Name rangeOfString:searchFilter.text options:NSCaseInsensitiveSearch];
if(codeRange.location != NSNotFound || nameRange.location != NSNotFound)
{
[filteredCourses addObject:course];
}
}
}
[table reloadData];
}
I still get the following error when running the script, I simply assumed it was due to the array being empty
2012-04-11 20:54:23.067 scheduleTable[45885:fb03] -[__NSArrayM Code]: unrecognized selector sent to instance 0x897b360
2012-04-11 20:54:23.068 scheduleTable[45885:fb03] *** WebKit discarded an uncaught exception in the webView:shouldInsertText:replacingDOMRange:givenAction: delegate: <NSInvalidArgumentException> -[__NSArrayM Code]: unrecognized selector sent to instance 0x897b360
My course.h and .m looks like this
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class Post;
#interface Course : NSManagedObject
#property (nonatomic, retain) NSString *Code;
#property (nonatomic, retain) NSString *Name;
#end
and
#import "Course.h"
#import "Post.h"
#implementation Course
#synthesize Code;
#synthesize Name;
#end
If I'm understanding your question correctly, to retain your array, declare the array in your .h file, like so:
#property (retain) NSMutableArray *yourArrayName;
Then,synthesize it in your .m file, like this:
#synthesize yourArrayName;
I tried using the retain method as Oral b answered but it got me nowhere, I am a bit of a newbie to Objective c which is why I am having the issues.
My courses array was declared in an interface and I was not able to achieve the same result with it as I did with the new array I created just for the search. So in ViewDidLoad I do this
coursesForSearch = [[NSMutableArray alloc] init];
Then where objects were added to my other array I simply added this array and also added the objects to it.
Now I can get objects from the array like so
[[coursesForSearch objectAtIndex:500] objectAtIndex:0]);

exc_bad_access from nsstring in an instance - HARD, BUT COOL

I have read the posts I found here and in many other places - no answers.
I have a simple class that contains NSString:
MyItem.h
#import <Foundation/Foundation.h>
#interface MyItem : NSObject
{
NSString * ItemName;
NSNumber * TestID;
NSMutableArray * Items;
}
//property
#property (nonatomic,retain) NSString * ItemName;
#property (nonatomic,retain) NSNumber * TestID;
#property (nonatomic,retain) NSMutableArray * Items;
// methods
-(id)initWithName:(NSString*)theName;
#end
MyItem.M
#import "MyItem.h"
#implementation MyItem
#synthesize Items;
#synthesize TestID;
#synthesize ItemName;
-(id)initWithName:(NSString*)theName
{
ItemName=theName;
Items=[[NSMutableArray alloc]init];
return self;
}
#end
It is very simple, as the class is created, the name is retained and the array allocated.
In order to have view controllers sharing this class, I have created this protocol:
MasterPager.h
#import <Foundation/Foundation.h>
#class MyItem;
#protocol MasterPager <NSObject>
#required
#property (nonatomic,retain) MyItem * currentItem;
-(void)dumpItems;
#end
which I then use in my appdelegate:
ArrayTestAppDelegate.h
#import <UIKit/UIKit.h>
#import "MasterPager.h"
#class ArrayTestViewController;
#interface ArrayTestAppDelegate : NSObject <UIApplicationDelegate,MasterPager>
{
//MyItem * currentItem;
}
#property (nonatomic,retain) MyItem * currentItem;
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet ArrayTestViewController *viewController;
#end
I'm instanciating this property in the application didFinishLaunchingWithOptions as so:
#synthesize currentItem;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
// Override point for customization after application launch.
currentItem=[[MyItem alloc] initWithName:#"main stuff"];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
self.viewController.mainPage=self;
return YES;
}
and here is the dumpItem method:
-(void)dumpItems
{
NSLog(#"Dumping %#",currentItem.ItemName);
for(int i=[currentItem.Items count]-1;i>=0;i--)
{
MyItem * item=[currentItem.Items objectAtIndex:i];
NSLog(#"current item id:%#", item.TestID );
NSLog(#"current item name:%#", item.ItemName );
}
}
(Sorry for all this text, but it is probably required).
Now, I have a view controller that I use in order to test this.
This view controller has 2 buttons, each of them triggers different function.
the first function to create some (4) sub items in this object is working fine:
-(IBAction)onCreate:(id)sender
{
for(int i=0;i<4;i++)
{
MyItem * item=[[MyItem alloc] initWithName :[NSString stringWithFormat:#"Test number %d",i]];
item.TestID=[NSNumber numberWithInt:i];
[mainPage.currentItem.Items addObject:item];
}
[mainPage dumpItems];
}
As you can see the dumpItems is called and it does what its suppose to do, dumping the objects.
********NOW... here is the thing!*************
There is a second button, as mentioned, that execute the same function:
- (IBAction)onDump:(id)sender
{
NSLog(#"executing dump on the protocol");
[mainPage dumpItems];
}
After creation, clicking the second button is calling this method which in turn calls the same dumpItems! BUT, when this is executed, an exc_bad_access is thrown when the line
NSLog(#"current item name:%#", item.ItemName );
is reached. comment the line and it's all working.
un-commenting the //MyItem * currentItem; will do nothing. So, how could it be?
NSZombieEnabled ? Tried that, did nothing.
There is no release call in sight, and if there were, how come the NSNumber dump working just fine?
Also, nothing happen between the first button clicked and the second one.
but still, the strings somehow disappears!
is this ARC? If not, it's not that hard, and not that cool ;-)
You pass an autoreleased NSString to your init method
MyItem * item=[[MyItem alloc] initWithName :[NSString stringWithFormat:#"Test number %d",i]];
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ autoreleased object
Unfortunately you don't retain that autoreleased string in your init.
-(id)initWithName:(NSString*)theName {
ItemName=theName; // <- no retain
}
the code steps out of the init method and you run dumpItems on the newly created object
[mainPage dumpItems]; // <- within same runloop iteration. AutoreleasePool has not be drained.
since you call dumpItems before the end of the current runloop the autoreleased object still exists.
But the IBAction method happens after the autoreleased object has been deallocated (the object was deallocated when the autorelease pool was drained at the end of the current runloop).
- (IBAction)onDump:(id)sender
{
NSLog(#"executing dump on the protocol");
[mainPage dumpItems]; // <- not in the same runloop. AutoreleasePool has been drained. Autoreleased object has been deallocated
}
the fix:
-(id)initWithName:(NSString *)theName
{
if ((self = [super init])) {
itemName = [theName retain]; // to match your #property
items = [[NSMutableArray alloc] init];
}
return self;
}
By the objective-c code style guidelines only Class names (e.g. NSString, MyItem) should start with a capital letter. You should fix this to improve readability (and the code formatting on stackoverflow)
I had the same problem, you should change the code from:
#property (nonatomic,retain) NSString * ItemName;
#property (nonatomic,retain) NSNumber * TestID;
#property (nonatomic,retain) NSMutableArray * Items;
to:
#property (nonatomic,copy) NSString * ItemName;
#property (nonatomic,copy) NSNumber * TestID;
#property (nonatomic,copy) NSMutableArray * Items;

Access modifier visibility in objective c

There are 3 modifiers: #private, #protected (default) and #public. So if i define a instance variable as private then that should not be accessible from anywhere.
For E.g. -
#interface A {
#private
NSString *a;
}
#property(nonatomic, retain) NSString *a;
Now inside implementation of some other interface/class B-
-(void)getSomeValue {
A *object = [[A alloc] init];
NSString *value = object.a;
.........
}
Here i am able to access instance variable, although i defined that as private.
It is a bit confusing, although when i look into details of this statement, then it is clear that it is calling the getter of a, but then also it seems confusing and it is against the concept of OOPS.
Anyone having any thought on this?
It's not the instance variable you're accessing but the property you declared. Don't declare the property if you do not want the instance variable to be visible outside the class.
#import <Foundation/Foundation.h>
#interface Visibility : NSObject {
#public
BOOL boolPublic;
#protected
BOOL boolProtected;
#private
BOOL boolPrivate;
}
#property (nonatomic, assign) BOOL boolPublic;
#property (nonatomic, assign) BOOL boolProtected;
#property (nonatomic, assign) BOOL boolPrivate;
#end
#implementation Visibility
#synthesize boolPublic;
#synthesize boolProtected;
#synthesize boolPrivate;
#end
int main(int argc, char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Visibility *visibility = [[Visibility alloc] init];
visibility.boolPublic = YES;
visibility.boolProtected = YES;
visibility.boolPrivate = YES;
// Place following NSLog()'s here
[pool release];
}
Let's try this out
Using the methods you define with #property/#synthesize
NSLog(#"Accessors %d %d %d", visibility.boolPublic, visibility.boolProtected, visibility.boolPrivate);
=> 2012-01-08 17:46:40.226 Untitled[2592:707] Accessors 1 1 1
Accessing #public ivar directly
NSLog(#"Public %d", visibility->boolPublic);
=> 2012-01-08 17:46:40.228 Untitled[2592:707] Public 1
Accessing #protected ivar directly
NSLog(#"Protected %d", visibility->boolProtected);
=> error: instance variable 'boolProtected' is protected
=> NSLog(#"Protected %d", visibility->boolProtected);
=> ^
Accessing #private ivar directly
NSLog(#"Private %d", visibility->boolPrivate);
=> error: instance variable 'boolPrivate' is private
=> NSLog(#"Private %d", visibility->boolPrivate);
=> ^
When you are accessing using dot notation this:
visibility.boolPublic
is equivalent to:
[visibility boolPublic]; // <- This is a method call
Because you set it as a #property and you claim it in header file. The variable you set as a #property will auto generate getter and setter for this variable and they are both public method to get or set it(variable is still private). If you really want to make the property as an private method, you should claim it in .m file and it will become private. You can only use this variable in the .m file.
For example, in your .h file
#interface ClassWithPrivateProperty : NSObject {
#private
NSString* member;
}
- (void) trySettingPrivateProperty;
#end
in your .m file
#import "ClassWithPrivateProperty.h"
#interface ClassWithPrivateProperty ()
#property (nonatomic,retain) NSString* member;
#end
#implementation ClassWithPrivateProperty
#synthesize member;
- (void) trySettingPrivateProperty {
self.member = #"A Value";
NSLog(#"myClass.member = %#", self.member);
}
#end
You can check more detail in Private properties for iPhone Objective-C
Edit:
Thanks for Abizern and Paul's comment, but in fact I got nothing compile error for this program.
I think RIP's question is "Why I set the variable in #private but I can still modify the variable like instance.variable"
The answer is although he set the variable as #private, but claim #property for variable in .h file also provide public methods getter and setter. So he can still get the instance variable use instance.variable. For OOP design pattern you should not expose your internals publicly. So if you want to use a variable privately only in its class and no one know it. And you still want to use getter and setter to access this variable in its class. you should claim #property in .m file like I did above. I claim the #property in .m file, it's a #interface extension(unnamed category). So you can make it "like" private. Because you cannot access this variable from anywhere outside this class. So it's just like a "private #property" that I mention about.
Two useful articles for you Public Properties with Private Setters and Private properties for iPhone Objective-C

iPhone: initialize object in controller

I am very new to objective-c and having a problem to initialize an object in view controller. The problem I am having is that when setTemp method is called, "0" is printed on the screen instead of the value of cTemp I would like it to be. Can anyone help me on this problem?
Below are excerpts of the code I have.
SJT.h
#import <Foundation/Foundation.h>
#import <stdlib.h>
#interface SJT : NSObject {
int cTemp;
}
- (int) newTemp;
#end
SJT.m
#import "SJT.h"
#implementation SJT
- (int) newTemp
{
cTemp = 25 + rand() % 8;
return cTemp;
}
#end
SJTViewController.h
#import <UIKit/UIKit.h>
#class SJT;
#interface SJTViewController : UIViewController {
IBOutlet UILabel *temp;
SJT *sjt;
}
#property (retain, nonatomic) UILabel *temp;
#property (retain, nonatomic) SJT *sjt;
- (IBAction) setTemp: (id) sender;
#end
SJTViewController.m
#import "SJTViewController.h"
#import "SJT.h"
#implementation SJTViewController
#synthesize temp;
#synthesize sjt;
- (IBAction) setTemp: (id) sender
{
NSString *tempText = [[NSString alloc] initWithFormat:#"%d",sjt.newTemp];
temp.text = tempText;
[tempText release];
}
.
.
.
#end
The problem is that you're mistaking property syntax for a method call; i.e.
sjt.newTemp
would become a call to [sjt newTemp]. Which happens to be exactly what you want, except that you have not specified in your header/implementation that there actually is a property called newTemp.
So, in this scenario what you want to do is either a) define the property in the header:
#property(nonatomic, readonly) int newTemp;
or b), just call the method newTemp:
[sjt newTemp]
Are you certain that sjt is not nil? You don't provide the code where and instance of SJT is constructed. In Objective-C you can call a method on a nil reference without error, and if you do so on a method that returns an int it will return 0.
So sjt.newTemp will return 0 if sjt is nil.
Both Jacob and teabot have pointed out valid possible reasons -- which one is correct (or both!) depends on pieces of code we can't see in your post.
Based on what you've written so far, you might not be thinking of newTemp as a property, but more as a function call, so I would suggest changing your code to:
- (IBAction) setTemp: (id) sender {
int tempInt = [self.sjt newTemp];
self.temp.text = [NSString stringWithFormat:#"%d", tempInt];
}
which is functionally equivalent. Note the convenience constructor stringWithFormat: returns an autoreleased object, which is then retained by the retain property text of the temp UILabel.
The other thing to double-check in your code is that self.sjt is not nil, which is exactly what teabot said. Objective-C returns 0 on method calls invoked on a nil pointer.