Noob question here.
If I have Class A with an array float itemsPosition[20][20] and I have another class B to access that, how can I do it?
What I usually do it to alloc Class A and access for other objects but in this case, I can't synthesize float array within Class A.
Any ideas?
You can #synthesize an NSValue that holds a pointer to your array.
#interface SomeObject : NSObject
#property (strong, nonatomic) NSValue *itemsPosition;
#end
#implementation SomeObject
#synthesize itemsPosition;
...
static float anArray[20][20];
...
- (void) someMethod
{
... add items to the array
[self setItemsPosition:[NSValue valueWithPointer:anArray]];
}
#end
#implementation SomeOtherObject
...
- (void) someOtherMethod
{
SomeObject *obj = [[SomeObject alloc] init];
...
float (*ary2)[20] = (float(*)[20])[obj.itemsPosition pointerValue];
...
}
Floats are C-types and so you can't use the typical Objective C property thing to access them directly.
Best thing to do is create an "accessor" function that gives class B access to the pointer for the very first array entry "itemsPosition". E.G. "itemsPosition[0][0]"
In class A's .h file:
float itemsPosition[20][20];
- (float *) getItemsPosition;
and in the .m file:
- (float *) getItemsPosition
{
// return the location of the first item in the itemsPosition
// multidimensional array, a.k.a. itemsPosition[0][0]
return( &itemsPosition[0][0] );
}
And in class B, since you know the size of this multidimensional array is 20 x 20, you can step to the location of the next array entry pretty easily:
float * itemsPosition = [classA getItemsPosition];
for(int index = 0; index < 20; index++)
{
// this takes us to to the start of itemPosition[index]
float * itemsPositionAIndex = itemsPosition+(index*20);
for( int index2 = 0; index2 < 20; index2++)
{
float aFloat = *(itemsPositionAIndex+index2);
NSLog( #"float %d + %d is %4.2f", index, index2, aFloat);
}
}
}
Let me know if it would be useful for me to put a sample Xcode project up for you somewhere.
Related
I'm working on this assignment I found online (Intermediate App Development Using iOS). I'm stuck on part c and d, don't know exactly what its asking me to do.
I know how to print int (%i) and object (%#), but %# print all data? Any help or suggestion will be appreciated.
Part 6
a) Implement class A with properties a1, a2, and a3 (int, string, int).
b) New objects are automatically initialized to 1, "hello", 1
c) Also provide initializer to any data and constructor (called without alloc) to do the same.
d) Make sure %# object of A will print all data.
Here is what I have done so far:
// classA.h
#import <Foundation/Foundation.h>
#interface ClassA : NSObject
// Part 6a
#property int a1;
#property NSString *a2;
#property int a3;
-(ClassA *) initWithA1: (int) x andA2: (NSString *) s andA3: (int) y;
#end
//classA.m
#import "ClassA.h"
#implementation ClassA
-(ClassA *) initWithA1:(int)x andA2:(NSString *)s andA3:(int)y {
self = [super init];
if (self) {
self.a1 = x;
self.a2 = s;
self.a3 = y;
}
return self;
}
// part 6b
-(ClassA *) init {
if (self = [super init]) {
self.a1 = 0;
self.a2 =#"hello";
self.a3 = 0;
}
return self;
}
#end
In reference to part "b" of your question:
As a general rule, only 1 initializer should be doing the "real" work. This is often referred to as the designated initializer. So, your init method should probably read something like:
- (id) init
{
return [self initWithA1:1 andA2:#"hello" andA3:1];
}
As #orbitor wrote, your class should have one designated initialiser.
So, your init method should probably read something like:
- (id) init
{
return [self initWithA1:1 andA2:#"hello" andA3:1];
}
In order to print all object you should implement custom description method:
- (NSString *) description
{
return [NSString stringWithFormat:#"a1 = %d, a2 = %#, a3 = %d", self.a1, self.a2, self.a3];;
}
According to c:
Class method new just calls alloc and init methods so you should only make sure that you wrote properly all initialisers.
I'm trying to take a C-style vector and convert it into an NSMutable array object.
Here's the function:
+(NSMutableArray*)arrayFromPoints:(vector<Point2f>&)points
{
NSMutableArray* pointArray = [[NSMutableArray alloc] init];
for (int i=0;i<points.size();i++)
{
Point2f point = points[i];
JBPoint* point2 = [[JBPoint alloc]initWithX:point.x andY:point.y];
[pointArray addObject:point2];
}
return pointArray;
}
Custom point class:
#implementation JBPoint
float _x;
float _y;
-(id) initWithX:(float)x andY:(float)y
{
if (self=[super init])
{
_x = x;
_y=y;
}
return self;
}
-(float)x{ return _x;}
-(float)y {return _y;}
#end
Test output:
for (JBPoint* pnt in array)
{
NSLog(#"%f, %f", pnt.x, pnt.y);
}
I except it to output the array, but every time it just gives me the last value! does anyone know why?
I thought that they were maybe pointing to the same object, but they have different memory addresses.
So I figured out the problem. float _x;
float _y; where being treated like class variables instead of instance variables. Changed the class to:
#interface JBPoint()
{
float _x;
float _y;
}
#end
#implementation JBPoint
-(id) initWithX:(float)x andY:(float)y
{
if (self=[super init])
{
_x = x;
_y=y;
}
return self;
}
-(float)x{ return _x;}
-(float)y {return _y;}
#end
if you wrote
#property (nonatomic, readonly) float x;
#property (nonatomic, readonly) float y;
in your header file you wouldn't need to declare the instance variables (and would have avoided the issue here) and you could delete the getter methods your wrote as that would all be generated by the compiler for you and your custom init method would continue to work (with the most recent compiler).
Its a good idea to do this because:
less code
your intent is clear - 2 variables that are readonly for clients
follows language conventions
If you are using an older compiler (an older version of Xcode) then you would also have to #synthesize the accessors like this:
#synthesize x = _x;
Some interesting asides:
With the most recent complier you didn't need the class extension.
#implementation{
float _x;
float _y;
}
would also have worked.
As referenced in WWDC 2012 session video 413, the current recommended pattern to write an init method is:
...
self = [super init];
if (self) {
...
}
return self;
I'm new in Objective C and stuck on this problem already 5 days)) What i have to do is write implementation for simple task about city and metropolis. I have class City with properties and class metropolis that has an global array which adds city object through createCity method. I have implemented this task but this arrays returns nothing.
Can anybody help me?
Here is part of the task:
1. Write a “City” class, which inherits from NSObject. Your class should contain the following:
Variables:
name, age, population.
Instance methods:
setName:age:population (single method) which set city’s name, age and population. getName, getAge, getPopulation which return city’s name, age and population, respectfully.
nextDay which adds a random number to city’s population, then subtracts a random number from city’s population. Figure out a way to generate random numbers yourself.
2. Create an instance of City class, set its name, age and population as you want.
3. Write a for-‐loop (if in doubt how to do it – google or use Xcode’s help system) for 10 steps. Each step send ‘nextDay’ message to your object and print out the population.
4. Write a “Metropolis” class. It should contain the following:
Variable:
array of 10 cities.
Instance method:
createCity:atIndex:withPopulation: (single method) which creates a city with first parameter being a name at index (from the second parameter) and sets its population to that of third parameter. So, you should be able to do this:
[myMetropolis createCity: #”Almaty” atIndex: 2 withPopulation: 1500000]
5. Create an instance of Metropolis class and create all 10 cities.
Here is my implementation:
City.h
#import <Foundation/Foundation.h>
#interface City : NSObject
{
NSString* name;
int age;
int population;
}
-(void)setName: (NSString*)n age: (int)a population: (int)p;
-(NSString*)getName;
-(int)getAge;
-(int)getPopulation;
-(void)nextDay;
#end
City.m
#import "City.h"
#implementation City
-(void)setName:(NSString*)n age:(int)a population:(int)p
{
name = n;
age = a;
population = p;
}
-(NSString*)getName
{
return name;
}
-(int)getAge
{
return age;
}
-(int)getPopulation
{
return population;
}
-(void)nextDay
{
int r = arc4random() % 100;
int r2 = arc4random() % 100;
population = population + r;
population = population - r2;
}
#end
Metropolis.h
#import <Foundation/Foundation.h>
#import "City.h"
#interface Metropolis : NSObject{
NSMutableArray* myArray;
}
-(void)createCity: (NSString*)n atIndex: (int)a withPopulation: (int)p;
-(NSMutableArray*) getArray;
#end
Metropolis.m
#import "Metropolis.h"
#import "City.h"
#implementation Metropolis
NSMutableArray* myArray = nil;
- (void)initialize {
myArray = [[NSMutableArray alloc]initWithCapacity:10];
}
-(void)createCity:(NSString*)n atIndex:(int)a withPopulation:(int)p
{
City* newCity = [[City alloc]init];
[newCity setName:n age:0 population:p];
[myArray insertObject:newCity atIndex:a];
}
-(NSMutableArray*)getArray
{
return myArray;
}
#end
main.m
#import <Foundation/Foundation.h>
#import "City.h"
#import "Metropolis.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
Metropolis* myMetropolis = [[Metropolis alloc]init];
[myMetropolis createCity:#"Aktobe" atIndex:0 withPopulation:15];
[Metropolis initialize];
NSMutableArray* c = [[NSMutableArray alloc]init];
c = [myMetropolis getArray];
NSLog(#"%#", [[c objectAtIndex:0] getName]);
}
return 0;
}
The method for initialization is -(void)init; this method should be overwritten in your implementation of Metropolis.
You are calling - (void)initialize; which is wrong in this case.
So, simply change - (void)initialize { to -(void)init { in your implementation of Metropolis and delete the line: [Metropolis initialize]; in main.
After the comment below the proper init method should be:
-(id) init {
self = [super init];
if (self) {
myArray = [[NSMutableArray alloc]initWithCapacity:10];
}
return self;
}
I've rewritten my answer to make it more complete, and to incorporate some of the other ideas generated in the other answers, especially #Hannes Sverrisson
The easy way to fix your issue is to call initialize BEFORE createCity (otherwise your trying to add objects to a nil array) and to also make sure you're not calling initialize from a static context. i.e. change [Metropolis initialize]; to [myMetropolis initialize];
The better way, and by better I mean more consistent with typical objective-c design, you should override the instance method init. This is done in the Metropolis implementation and replaces your initialize method.
-(id) init {
self = [super init];
if (self) {
myArray = [[NSMutableArray alloc]initWithCapacity:10];
}
return self;
}
or to make it more fun, create a new init method that takes the number of cities as a parameter.
-(id) initWithNumberOfCities:(NSInteger)numCities {
self = [super init];
if (self) {
myArray = [[NSMutableArray alloc]initWithCapacity:numCities];
}
return self;
}
Then in your main method, remove the call to [Metropolis initialize]. The reason for this is when you say:
Metropolis* myMetropolis = [[Metropolis alloc]init];
or
Metropolis* myMetropolis = [[Metropolis alloc]initWithNumberOfCities:10];
the init method is being called inline after the allocation takes place.
You don't need to write getters or create backing instance variables. You can use Objective-C 2.0's #property syntax.
#property (strong) NSString *name;
#property (assign) NSInteger age;
#property (assign) NSInteger population;
- (void)setName:(NSString*)name age:(NSInteger)age population:(NSInteger)population;
- (void)nextDay;
Then you access the properties using self.name, self.age, self.population or if you need to access the backing variable itself, _name, _age, _population.
I've got an c-struct array, and want to define a property.
Here is the relative code..
struct Vertex {
float x, y, z;
float nx, ny, nz;
float u, v;
};
#interface Mesh : NSObject{
Vertex m_vertices[MaxVertices];
}
#property (nonatomic) Vertex m_vertices[MaxVertices];
#end
#implementation Mesh;
#synthesize m_vertices[MaxVertices];
#end
I first wrote like this with an error.
how to set the property with c-struct array, or customlize the setter and getter?
Any tips will be appreciated!
Use
#property (nonatomic) Vertex *m_vertices;
and
#synthesize m_vertices;
instead. You can't use a static array like this; malloc() it using something like this in your constructor and free() in the destructor:
- (id)init
{
if ((self = [super init]))
{
m_vertices = malloc(sizeof(*m_vertices) * NUM_OF_VERTICES);
}
return self;
}
- (oneway void)dealloc
{
free(m_vertices);
[super dealloc];
}
This was a close as I could get.
typedef struct _Vertex {
float x, y, z;
float nx, ny, nz;
float u, v;
} Vertex;
#define MaxVertices 5
#interface Mesh : NSObject{
Vertex m_verticesX[MaxVertices];
Vertex *m_vertices;
}
#property (nonatomic) Vertex *m_vertices;
#end
#implementation Mesh;
#synthesize m_vertices;
- (Vertex *)m_vertices
{
if (!m_vertices)
m_vertices = m_verticesX;
return m_vertices;
}
#end
Hope it helps.
You cannot use arrays as properties. You can do two things:
1) Use a NSArray or NSMutableArray to hold objects instead of structs.
or
2) Put the array in a structure:
typedef struct VertexArray
{
struct Vertex m_vertices [MaxVertices];
};
#property (nonatomic, assign) VertexArray* m_vertices;
or
3) Put the array in an object
#interface VertexArray
{
struct Vertex m_vertices [MaxVertices];
}
- (struct Vertex)getVertexofIndex:(NSUInteger)index;
- (void)setVertex:(struct Vertex)vertex atIndex:(NSUInteger)index;
#end
and for the property in Mesh:
#property (nonatomic, retain) VertexArray* m_vertices;
or you can put the contents of VertexArray directly within Mesh (i.e. the member variable and two accessor methods).
When you return an array of (any type) in C, you are returning the first index of the array.
So if I wanted to return the variable below that was declared in the interface.
Vertex m_vertices[MaxVertices];
I could say...
- (Vertex *)m_vertices
{
return m_vertices;
}
This above is the same thing as saying...
- (Vertex *)m_vertices
{
return &m_vertices[0];
}
If you wanted to return the entire array back however, the best way to do this would probably be to use memcpy directive.
memcpy(<#void *#>, <#const void *#>, <#size_t#>)
Reference it here: http://www.cplusplus.com/reference/cstring/memcpy/
Write the function like this...
- (Vertex *)m_vertices
{
Vertex *localVertex;
memcpy(localVertex,&m_vertices,sizeof(Vertex)* MaxVertices);
return localVertex;
}
This copies the literal bytes over and is very fast. It will return the entire array back.
The better way to do this would be to make a function like this possibly as well.
- (Vertex *)m_vertices_nthIndex:(int)index
{
return(&m_vertices[index]);
}
This way you can get the index of whatever item you need.
Usually I treat instance variables in Objective-c like this:
#interface MyClass : NSObject
#property (nonatomic, retain) NSMutableArray *mutableArray;
#end
#implementation MyClass
#synthesize mutableArray;
- (id) init {
if((self = [super init])) {
self.mutableArray = [NSMutableArray array];
}
return self;
}
- (void) dealloc {
[mutableArray release];
[super dealloc];
}
#end
I feel pretty comfortable w/ the above syntax. However I'm not so comfortable w/ the syntax for a 2D array instance variable like NSUInteger 2dArray[10][10].
What's the appropriate Objective-c syntax for a 2d array instance variable with regards to interface declaration, synthesizing getters/setters and memory management?
You don't need to allocate memory for your array; they are perfectly fine being defined in the class and they will always exist, at the same size. You therefore don't need to worry about memory management and your getter/setters should be defined manually, depending on what you want to do. For example these getter/setter methods allow getting/setting an individual value:
#interface MyClass : NSObject
{
NSUInteger _twoDeeArray[10][10];
}
- (void)setTwoDeeArrayX:(NSUInteger)x y:(NSUInteger)y value:(NSUInteger)value;
- (NSUInteger)twoDeeArrayX:(NSUInteger)x y:(NSUInteger)y;
#end
#implementation MyClass
- (void)setTwoDeeArrayX:(NSUInteger)x y:(NSUInteger)y value:(NSUInteger)value
{
_twoDeeArray[x][y] = value;
}
- (NSUInteger)twoDeeArrayX:(NSUInteger)x y:(NSUInteger)y
{
return _twoDeeArray[x][y];
}
#end
You should probably have range-checking for x and y, but you get the idea.
That's not an Objective C syntax. It's pure C syntax. You don't need to exclusively say that you want a 2D array of objc objects. Just declare/define the mutable array and add other arrays to it.
For two-demensional arrays, you can:
Go with C arrays (like what you mentioned in the post)
Add NSMutableArray into NSMutableArray
Create a class to implement your version of 2D-array
If you just want to use primitive types in your array, all three are good.
For Objective-C objects, you can also go with C array with id type but you have to manage memory allocation/deallocation yourself. 2 and 3 are better way to do this.
FYI:
2D arrays using NSMutableArray
Creating a two dimensional array in Objective-C
in iOS 6 you can use subscript to define a matrix class that uses the square bracket syntax matrix[row][col] where you can store objects and they are correctly retained by the matrix, differently than using a C array
First create a Row object, defined like this
- (id)initWithElementNumber:(NSUInteger)num {
if (self = [super init]) {
_row = [NSMutableArray arrayWithCapacity:num];
for (int j = 0; j < num; j++)
[_row addObject:[NSNull null]];
}
return self;
}
- (id)objectAtIndexedSubscript:(NSUInteger)idx {
return self.row[idx];
}
- (void)setObject:(id)object atIndexedSubscript:(NSUInteger)idx {
self.row[idx] = object;
}
#end
And then a Matrix class that uses the Row class previously defined:
#implementation UKMatrix
- (id)initWithRows:(NSUInteger)numRows columsn:(NSUInteger)numCol {
if (self = [super init])
{
_numCol = numCol;
_numRows = numRows;
_rows = [NSMutableArray arrayWithCapacity:numRows];
for (int j = 0; j < numRows; j++)
[_rows addObject:[[UKRow alloc] initWithElementNumber:numCol]];
}
return self;
}
- (id)objectAtIndexedSubscript:(NSUInteger)idx {
return self.rows[idx];
}
- (NSString *)description {
NSString *matrixDesc = #"";
for (int j = 0; j < self.numRows; j++) {
matrixDesc = [matrixDesc stringByAppendingString:#"\n"];
for (int k = 0; k < self.numCol; k++)
matrixDesc = [matrixDesc stringByAppendingFormat:#" %# ",self[j][k]];
}
return matrixDesc;
}
#end
then you can use the Matrix with the following syntax
UKMatrix *matrix = [[UKMatrix alloc] initWithRows:4 columsn:2];
matrix[1][1] = #2;
NSLog(#"%#", matrix);