Array object doesn't retain it's data - objective-c

I have an object that contains a array. On initialization of this object, the array is allocated and properly filled (as I can see in the debugger). This object is use to manage elements in a single view.
My problem is that when I try to call the object a second time, the array (and all other parameter of this object) are nil yet they have a memory address (again as seen in debugger).
This is the .h of the object in question :
#import <Foundation/Foundation.h>
#import "ObjectDef.h"
#import "AbstractNode.h"
#interface RenderingMachine : NSObject
{
NSMutableArray* _objectID; // pair list
NSMutableArray* _objectList; // node list
ObjectDef* _defs; // definition of pairs
unsigned int _size;
unsigned int _edgeSize;
AbstractNode* _lastNode;
}
-(void) InitializeMachine;
-(bool) AddObjectByIndex:(int)index :(float)x :(float)y :(float)originX :(float)originY;
-(bool) AddObjectByType:(NSString*)type;
-(NSMutableArray*) GetObjectID;
-(NSMutableArray*) GetObjectList;
-(unsigned int) Size;
-(void) DrawAllNode;
-(int) ComputePar;
-(void) ComputeLastEdge:(int)edgeCount;
//+(RenderingMachine*) GetMachine;
#end
My main problem right now is with _defs which is filled in InitDefinitions :
-(void) InitializeMachine
{
_defs = [[ObjectDef alloc] init];
[_defs InitDefinitions];
_objectID = [[NSMutableArray alloc] init];
_objectList = [[NSMutableArray alloc] init];
_objectID = [NSMutableArray arrayWithObject:[_defs GetPair:3]]; // adding the field node ID
AbstractNode* rootNode = [[FieldNode alloc] init];
_objectList = [NSMutableArray arrayWithObject:rootNode]; // adding the field node as root node
_size = 1;
_edgeSize = 0;
}
What I'd like to know is if might be a bad alloc / init call or could it be a problem with the ARC of xcode because this particular file compiles with ARC (the other being ignore with "-fno-objc-arc").
Also, as mentionned the _defs is problematic, but all the property declared under #interface are having the same problem.

First you create a retained object with _objectID = [[NSMutableArray alloc] init];
and then you overwrite it with an autoreleased one _objectID = [NSMutableArray arrayWithObject:[_defs GetPair:3]];
to add the object better use [_objectID addObject:[_defs GetPair:3]];
same thing with the _objectList Object

Related

How to add new array element from another method in Objective-c?

I have some array( #private NSArray employees []; ) and method , which take string parameter( name of employees) and put this parameter in array. How I can do this with Objective-c?
You could do the following,
Create a property,
#property (nonatomic) NSMutableArray *array;
Initialise the array in your init method or somewhere else appropriate,
self.array = [[NSMutableArray alloc] init];
Your method could look something like this,
- (void)addEmployeeName:(NSString *)employeeName {
[self.array addObject:employeeName];
}
You can create a class Employee and use a type with your array.
For example:
NSArray<Employee*> * employees = [[NSArray alloc] init];
At this point, your method will be:
-(Employee *)createEmployee:(NSString *)name{
Employee *myEmpl = [[Employee alloc]init];
[myEmpl setName:name];
return myEmpl;
}
and you can add the object (of type Employee) in your array in this way:
[employees addObject:[self createEmployee]];
the same thing is possibile with an object of type NSString instead of Employee.
You can also avoid defining the type in your NSArray because Objective-C use the type inference

how do I set the values of an array in Objective-C using .notation?

Sorry I'm new to Objective-C and I'm still figuring out how to set properties using dot notation. I have 3 files as follows... towards the end(in main), I've set the radius property and the logged it, but I'm not sure how to set the center property because it's not a float (like radius) it's an array. I originally tried something like—
ball.center = {12, 14, 16} does not work.
My class .m file is:
#implementation Sphere
-(void)setCenter:(NSArray *)center radius:(float)radius {
_center = center;
_radius = radius;
}
#end
my class .h file is:
#interface Sphere : NSObject
#property (nonatomic) float radius;
#property (nonatomic, strong) NSArray *center;
-(void)setCenter:(NSArray *)center radius:(float)radius;
#end
and my main file is:
int main(int argc, const char * argv[])
{
#autoreleasepool {
Sphere *ball = [[Sphere alloc] init];
ball.radius = 34;
**// ball.center = an array, so how do we set that?**//
**//do I have to set the values of the array first?//**
NSLog(#"\nball radius %f\n", ball.radius);
**//I want to be able to log the values of the array the way I logged the radius.**
}
return 0;
}
I'll reply to your question "how I can create an array with numbers", but it looks like you don't need an array at all (read all the answer :-))
The first thing that you need is to initialize your array, for example:
NSArray *array = [NSArray arrayWithObjects:object1, object2, object3, nil];
There is also the literal that allows you to do the same thing with a friendly synthax
NSArray *array = #[object1, object2, object3];
Note that you can only insert objects in an NSArray and not primitives, so you need some NSNumber (a NSNumber is an object that represents a number).
You can use a class method to create a NSNumber
NSNumber *one = [NSNumber numberWithInt:1];
Or the literal synthax (usually preferred for its brevity)
NSNumber *one = #(1);
So, something like this will do
NSArray *array = #[#(1), #(2), #(3)];
However, I see that you want to represent the center, usually to do it, you don't use an array of objects, you use a CGPoint, that is not an array, it is a struct that contains 1 point (i.e. X and Y), and it is perfect to represent the center!
So the code will look like:
#implementation Sphere
-(void)setCenter:(CGPoint)center radius:(float)radius {
_center = center;
_radius = radius;
}
#end
and to use it:
Sphere *ball = [[Sphere alloc] init];
ball.center = CGPointMake(10, 20);
NSLog(#"my ball center x:%d y:%d", ball.center.x, ball.center.y);

Objective C: Memory Management, releasing an object with multiple references

I would like to release a Car object present in the dealer. I would like to know what is the right way of doing it. NSMutableArray Inventory stores the cars for a particular dealer. So, now I would like to present the user with a delete functionality, so, user could select the car using the Vin Number and delete it. But if I try to find the car and release the reference that doesn't works. Would I need to remove the object from the Array and then, release the reference? I am fairly new to objective c and in the initial learning phase. Thank you.
#import "Dealer.h"
#import "Address.h"
#import "PhoneNumber.h"
#implementation Dealer
static NSInteger dealerIdAllocater = 0;
-(id) init{
self = [super init];
self.dealerId = ++dealerIdAllocater;
self.addressList = [[NSMutableArray alloc] init];
self.inventory = [[NSMutableArray alloc] init];
return self;
}
#synthesize dealerId, name, addressList, inventory;
-(void)addCarInInventory:(Car*)car{
[self.inventory addObject: car];
}
-(void)displayAddresses{
for(Address *address in self.addressList){
NSLog(#"Street Address: %#", address.streetAddress);
NSLog(#"City: %#", address.city);
NSLog(#"State: %#", address.state);
NSLog(#"Country: %#", address.country);
for(int i=0; i<[address.phoneNumber count]; i++){
PhoneNumber *phoneNumber = [address.phoneNumber objectAtIndex:i];
NSLog(#"Phone Number %i, %#", i, phoneNumber.phoneNumber);
}
NSLog(#"--------------");
}
}
-(void)displayInventory{
for(Car *car in self.inventory){
[car displayInformation];
}
NSLog(#"--------------");
}
-(Car *)findCarById:(NSString *)vinNumber{
for(Car *car in self.inventory){
if ([vinNumber isEqualToString:car.vinNumber]) {
return car;
}
}
return nil;
}
#end
Would I need to remove the object from the Array and then, release the reference?
Yes, containers such as NSMutableArrays increment the retain count of objects by 1 when added to them. This is to make sure the container will always hold a valid reference to an object. When you remove an object from the container, the retain count will be decremented by 1.

Objective C enumeration type in object changing on reassignment

I have searched and can't find the assert to this. I know it must be a fundamental thing I'm missing here.
I have an enum:
typedef enum {
NINETYBEND, NINETYBEND_FAST, NINETYBEND_SLOW, STRAIGHT
} BlockTypeEnum;
I am trying to use these values in objects I am creating like this:
BlockTypeEnum blockType = STRAIGHT;
XMLLevelPiece* piece = [[XMLLevelPiece alloc] init];
[piece initPiece:blockType];
My problem occurs when I try to use the same variable twice. If I create one object with an enum, change the enum and then create a second object using it, the enum in my first object changes to the second enum value. This is not what I want. Example below:
BlockTypeEnum blockType = STRAIGHT;
XMLLevelPiece* piece = [[XMLLevelPiece alloc] init];
[piece initPiece:blockType];
blockType = NINETYBEND_FAST;
XMLLevelPiece* piece2 = [[XMLLevelPiece alloc] init];
[piece2 initPiece:blockType];
NSLog([NSString stringWithFormat:#"%d", [piece getBlockType]]);
NSLog([NSString stringWithFormat:#"%d", [piece2 getBlockType]]);
//BOTH BLOCK TYPES ARE NOW NINETYBEND_FAST, NOT WHAT I WANTED!!
As far as I understood, an enum is just a glorified int, not a pointer, and I am reassigning the variable after adding to the first object. Please can someone tell me what I'm missing! Thanks very much, Simon.
Here is my code for XMLPiece, thanks!
#import "XMLLevelPiece.h"
#import "BlockType.h"
#import "GridCord.h"
#import "BlockColor.h"
#implementation XMLLevelPiece
BlockTypeEnum mBlockType;
BlockColorEnum mBlockColor;
int mRotation;
GridCord* mGridCords;
BlockColorEnum mLeftColor;
BlockColorEnum mTopColor;
BlockColorEnum mRightColor;
Boolean mRotatable;
Boolean mMoveable;
int mGroupID;
-(id) init
{
if( (self=[super init])) {
}
return self;
}
-(void)initPiece:(BlockTypeEnum)pBlockType pBlockColor:(BlockColorEnum)pBlockColor pRotation:(int)pRotation pGridCords:(GridCord*)pGridCords pLeftColor:(BlockColorEnum) pLeftColor pTopColor:(BlockColorEnum) pTopColor pRightColor:(BlockColorEnum) pRightColor pRotatable:(Boolean) pRotatable pMoveable:(Boolean) pMoveable pGroupID:(int) pGroupID
{
mBlockType = pBlockType;
mBlockColor = pBlockColor;
mRotation = pRotation;
mGridCords = pGridCords;
mLeftColor = pLeftColor;
mTopColor = pTopColor;
mRightColor = pRightColor;
mRotatable = pRotatable;
mMoveable = pMoveable;
mGroupID = pGroupID;
}
-(void)initPiece2
{
NSLog(#"poo");
}
-(Boolean)getRotatable
{
return mRotatable;
}
-(Boolean)getMoveable
{
return mMoveable;
}
-(int) getGroupID
{
return mGroupID;
}
-(BlockColorEnum) getLeftColor
{
return mLeftColor;
}
-(BlockColorEnum) getTopColor
{
return mTopColor;
}
-(BlockColorEnum) getRightColor
{
return mRightColor;
}
-(BlockTypeEnum) getBlockType
{
return mBlockType;
}
-(BlockColorEnum) getBlockColor
{
return mBlockColor;
}
-(int) getRotation
{
return mRotation;
}
-(id) getGridCords
{
return mGridCords;
}
-(void) setRotatable:(Boolean) pRotatable
{
mRotatable = pRotatable;
}
-(void) setMoveable:(Boolean) pMoveable
{
mMoveable = pMoveable;
}
#end
TL;DR
The answer is - that is not how you define ivars in Objective-C. I'm not even sure how that is supposed to behave but I can reproduce the error if I code it the same as you have.
I'd be interested for someone with more knowledge to explain what the behaviour/scope of those variable should be when they are defined like you have.
There's a lot of flaws in that code
You have not actually shown an initPiece:.
The long init... with all the arguments is likely a bad idea. Generally only add things to an init as either a convenience or if the object simply cannot function without it.
The use of get is not really correct in Objective-C
The class should potentially be defined more like
XMLLevelPiece.h
// You will need to import the header with the BlockTypeEnum defined
#interface XMLLevelPiece : NSObject
#property (nonatomic, assign) BlockTypeEnum blockType;
// .. Other properties
- (id)initWithPiece:(BlockTypeEnum)blockType; // I'm not so sure you need this
#end
XMLLevelPiece.m
#import "XMLLevelPiece.h"
#import "BlockType.h"
#import "GridCord.h"
#import "BlockColor.h"
#implementation XMLLevelPiece
#synthesize blockType = mBlockType;
- (id)initWithPiece:(BlockTypeEnum)blockType;
{
self = [super init];
if (self) {
mBlockType = blockType;
}
return self;
}
#end
Then you can use it like
BlockTypeEnum blockType = STRAIGHT;
XMLLevelPiece *p1 = [[XMLLevelPiece alloc] initWithPiece:blockType];
blockType = NINETYBEND_FAST;
XMLLevelPiece *p2 = [[XMLLevelPiece alloc] initWithPiece:blockType];
NSLog(#"%d", p1.blockType);
NSLog(#"%d", p2.blockType);
Which for me results in:
2012-01-08 15:29:31.782 Untitled[1297:707] 3
2012-01-08 15:29:31.791 Untitled[1297:707] 1
Optional observations
If you can do away with the dedicated initializer, the usage would look more like:
BlockTypeEnum blockType = STRAIGHT;
XMLLevelPiece *p1 = [[XMLLevelPiece alloc] init];
p1.blockType = blockType;
// all other assignments
blockType = NINETYBEND_FAST;
XMLLevelPiece *p2 = [[XMLLevelPiece alloc] init];
p2.blockType = blockType;
// all other assignments
NSLog(#"%d", p1.blockType);
NSLog(#"%d", p2.blockType);
To remove a couple of superflous lines you could remove the local blockType variable and assign the value straight to the object:
XMLLevelPiece *p1 = [[XMLLevelPiece alloc] init];
p1.blockType = STRAIGHT;
Your method call to initWithPiece does not match the definition.
Call:
[piece initPiece:blockType];
Definition:
-(void)initPiece:(BlockTypeEnum)pBlockType pBlockColor:(BlockColorEnum)pBlockColor pRotation:(int)pRotation pGridCords:(GridCord*)pGridCords pLeftColor:(BlockColorEnum) pLeftColor pTopColor:(BlockColorEnum) pTopColor pRightColor:(BlockColorEnum) pRightColor pRotatable:(Boolean) pRotatable pMoveable:(Boolean) pMoveable pGroupID:(int) pGroupID
Comments:
In general method calls with more than a few parameters are best a poor idea. Probably better in this case is using individual setters.
The convention in Objective-C as per Apple is to name getters without the "get" prefix. In fact a get prefix signifies a value returned via a reference parameter, not as the return result. Such usage will confuse the Analyzer and cause problems if using ARC.

Method to instantiate objects

Would like to create a method that instantiate objects. 
- (NSArray *) make3Of : (Class) type
{
...
type * temp = [[type alloc] ...
...
}
But I get a warning from Xcode ...
Actual warning:
"Class method +alloc not found (return type defaults to 'id')"
Is there a better/correct way to do this?
Actual code:
- (NSArray *) getBoxesOfType: (Class <ConcreteBox>) type StartingFrom: (uint64_t) offset
{
NSMutableArray *valueArray = [[NSMutableArray alloc]initWithObjects: nil];
for (uint64_t i = offset; i< boxStartFileOffset + self.size; i += [self read_U32_AtBoxOffset:i])
{
if ([[self read_String_OfLen:4 AtBoxOffset:offset + 4] isEqual:[type typecode]]) {
[[type alloc]initWithFile:file withStartOffset:i]; //warning here;
//yes I plan to assign it to a variable
//(originally of "type" but that won't work as AliSoftware pointed out, will be using "id" instead.
...
}
}
}
Same as example, I'm trying to instantiate a couple of objects.
Code for protocol:
#import <Foundation/Foundation.h>
#protocol ConcreteBox
+ (NSString *) typecode;
- (id) initWithFile: (NSFileHandle *) aFile withStartOffset: (uint64_t) theOffset;
#end
You can't use a variable (in your case type)... as a type for another variable!
In your code, both type and temp are variables, that's a syntax error.
As you don't know the type of the variable as compile time, use the dynamic type id instead. This type is specifically designed to handle cases when the type is not defined at compile time.
So your code will look like this:
-(NSArray*)make3Of:(Class)type {
id obj1 = [[[type alloc] init] autorelease];
id obj2 = [[[type alloc] init] autorelease];
id obj3 = [[[type alloc] init] autorelease];
return [NSArray arrayWithObjects:obj1, obj2, obj3, nil];
}