I am working on an iphone app in objective-c and I am having trouble with making an array out of a class variable, for example...
I have a class named Cube and I am tryin to make an instance of this class named map that is an array
Cube map[10][10];
Xcode then says it is an error and suggests I do this
Cube *map[10][10];
When I do it this way though ^ I cannot access one of my methods I defined in the class Cube, now this is not ALL my methods, it is just one single method that wont work anytime I try to call it. The only thing different about this method than the others is that I pass a parameter to it. The Cube class declaration and definition both compile flawlessly.
Can anyone explain to me how to make a class with a 2 dimensional without turning it into a pointer. Also why does xcode recommend I make it a pointer, and why doesn't the method work when I do it this way?
You probably want to use a Cocoa style array, i.e. NSArray or NSMutableArray instead of C-style array. It is much more flexible and is designed to work with Objective-c objects. Have a look at this simple tutorial on using a Cocoa array: http://iphonelearning.wordpress.com/2011/08/24/nsarray-and-nsmutablearray/.
The standard approach for this in Objective-C is to create an NSArray(or NSMutableArray) of an NSArray (or NSMutableArray). Assuming you want to be able to manipulate the array after you create the array object, your code would look something like this:
NSMutableArray* cubeGrid = [NSMutableArray new]; // Note that this code assumes you are using ARC.
// add row 1
NSMutableArray* cubeRow1 = [NSMutableArray arrayWithObjects:cube1,cube2,cube3,nil]; // you will need to add cube 4 to 10 in the real code
[cubeGrid addObject:cubeRow1];
// add row 2
NSMutableArray* cubeRow2 = [NSMutableArray arrayWithObjects:cube11,cube12,cube13,nil]; // you will need to add cube 14 to 20 in the real code
[cubeGrid addObject:cubeRow2];
// and you will create the rest of the rows and add to the cubeGrid array
To access the elements you would do something like this:
for (id cubeRow in cubeGrid) {
if ([cubeRow isKindOfClass:[NSArray class]]) {
for (id cube in (NSArray*)cubeRow) {
if ([cube isKindOfClass:[Cube class]]) {
// Do things with cube
}
}
}
}
What you might also want to double check is whether the method that you are trying to access is declared in the header file.
You may want to take a look at this this answer.
Related
Is it possible to check and get the name of the class an object was initialized in?
Example: I have Class A. I created object ABObject using [[ABOBject alloc] init]; via an instance method.
How can I find out the class from which an instance ABObject was created, namely "A" here?
Objects can be created outside the context of a class, so it wouldn't make sense for this to be a built-in language feature.
If you do have to do this, one way to work around it would be to use the objc_setAssociatedObjects() function in objc/runtime.h immediately after any such object was instantiated. Something like:
ABObject *object = [[ABObject alloc] init];
objc_setAssociatedObject(object, #"InstantiatingClassKey", [self class], OBJC_ASSOCIATION_ASSIGN);
Then you could get it with objc_getAssociatedObject(object, #"InstantiatingClassKey").
I think you'd be better off re-assessing your design because this is not going to be particularly maintainable. Even extracting this into a category on NSObject to remove duplicated code you'll still have an extra step to remember and weird relationships between your objects.
Also, as Martin R. points out in the comments, I'm taking a shortcut and passing a string literal as the key argument for the function, in reality you'd want to follow the practice of using the address of some static or global variable.
I have a for in loop where I do not quite get the objects I expect to get.
I have a CCLayer class called MainLayer where I add children of class MyUniqueClass. However if I try to get all MyUniqueClass objects, I get other CCNode objects as well. Here's what I do in MainLayer:
for (MyUniqueClass *mUC in self.children){
NSLog(#"%#", mUC); //Here I get all kinds of objects
}
Try to figure out why the CCNode objects are there. Somehow they've been added as children.
Or just ignore that and do this to filter out other node classes:
Class uniqueClass = [MyUniqueClass class];
for (MyUniqueClass *mUC in self.children)
{
if ([mUC isKindOfClass:uniqueClass])
{
NSLog(#"%#", mUC);
}
}
You seem to believe that typing the loop variable as MyUniqueClass * will cause the loop to only cover objects belonging to that class. That isn't how fast enumeration works. It doesn't interact with the type checker at all. Giving a static type to the loop variable just lets the compiler do type checking on the things you do in the loop body (so it can warn you if, say, you're accidentally using a text field like a text view) and lets you access the object's properties with dot syntax. If you want to only operate on objects of a certain class, you'll have to explicitly check in your loop body as shown by LearnCocos2D.
I understand that:
(NSArray *)methodName
would return an array.
(UIImageView *)methodName
would return an imageview.
But how about if I wanted to return an Array of ImageViews?
If you're worried about it not being very clear about the fact that the array has UIImageViews, you can specify it on the name of the method, something like:
-(NSArray *)imageViewsForSomething:(id)something;
Otherwise, there's no reason you'd need to return explicitly an array of UIImageViews, an NSArray will do the trick.
Arrays and other container objects cannot be type in Objective-C like you can di in java.
One possible solution would be to subclass the NSArray class
NSArray is a stack of memory which stores object you add to it.
To store imagesviews, create an object of imageview and insert it in the array.
If you have to create long list of imageviews, you can create them using some iterative loop and add them in the array.
The array will hold on the imagesviews in it.
I am a newbie here, sorry if maid a mistake in above answer...
I have an array filled with instances of a custom class which contains two String properties, firstname and lastname. Both have a getter method which is equal to the name of the property itself. There is also a method for retrieving the Full name of a person called "getFullName". Consider the example below.
CustomClass *person = [[CustomClass alloc] ...];
person.firstname // Returns "Thomas"
person.lastname // Returns "Meier"
[person getFullName] // Returns "Thomas Meier"
Now I would like to sort this Array by Fullname in a descending Order. I have been looking at some array sorting methods but was not quite able to figure out how to go about this. I guess that I have to create some kind of comparison function which compares two elements, yet how do I tell the SDK which values to pass to this method and where should I place it (in the custom class or in the class where the sorting happens?). Maybe there is another/better way of going about this? Admittedly I have close to none experience with sorting arrays.
Thanks a lot for your help!
Ps. The code should run on iOS 3.2
There are a couple ways to do this. One is to put a comparison method on the custom class. Call it -compare: or something like that. That method should take another object of the same custom type as its input. It should return NSOrderedAscending, NSOrderedDescending, or NSOrderedSame, depending on the result of the comparison. (Inside this compare function is where you look at your own fullName versus the passed-in object's fullName.)
Then you can use NSMutableArray's -sortUsingSelector: method, like this:
[myArray sortUsingSelector:#selector(compare:)];
This works on all versions of iOS. There are block comparison methods available in 4.0+.
To optimize a bottleneck, I converted the creation of a large NSArray to a c-style array. (The resulting creation was 1/8 the time of the original NSArray version. Yeah!) But once it's created, speed is no longer an issue, so I'd rather benefit from it being an NSArray again.
However, it seems ridiculously involved to convert a c-style array to an NSArray (unless I'm missing some magic initWithArrayWrapElementsInObjects method.)
As I understand the process now, I first have to create an NSMutableArray, iterate through the c-style array converting each element (floats in my case) to objects, adding each object to the NSMutableArray, then creating the NSArray with the NSMutableArray.
Is that right? There's got to be a better way.
And help would be appreciated.
Thanks!
There's no direct way to take a blob of memory that you own and "convert" it cheaply into an NSArray-- after all, the framework would need to then own that memory, and it doesn't know where you got it from (malloc, stack, etc). If there were a convenience method for initWithArrayWrapElementsInObjects, it would itself need to do internally what you surmise: iterate over your provided memory and add items to itself (it's possibly the framework could do this as quickly as a memcpy, but who knows).
One way you could tackle this (and probably a fun learning exercise) is by actually creating your own subclass of NSArray that manages memory exactly as you want (ie, lets you create and init with whatever semantics you want), but that behaves to the outside world as an NSArray would. You can do this by inheriting from NSArray and implementing the methods count: and objectAtIndex: to operate on whatever memory you're holding on to. Obviously, you'd need to implement the management of your own memory in the init/dealloc, etc methods as well. See this page http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html
under "Subclassing Notes".
The design discussion here hinges on what your data looks like. NSArray, of course, expects its items to be Obj-C references (of type id), and not just arbitrary chunks of data. If your C-style array is holding structures or some other primitive values that aren't object references, then this technique won't really work for you-- NSArray's interface will never be happy with non-reference items.
One final note: you mention taking an NSMutableArray and "creating" an NSArray with it. You should be aware that an NSMutableArray is already an NSArray, since it's a subclass. You can use an instance of NSMutableArray anywhere you'd want an NSArray, without creating some new copy of it.
UPDATE: Missed the note about your array containing floats. Yeah, you're a little bit screwed here. NSArrays want objects. If the capacity doubling was the expensive part (as another poster notes), then try initWithCapacity:. If it's the boxing/unboxing of the floats into object types, there's nothing you can do.
I have created (but don't have handy) a pair of very simple classes (called like MYArray and MYMutableArray) that are intended to wrap just this kind of data with NSArray-like methods on them. But they're not interchangeable with NSArrays. You must use them intentionally.
UPDATE #2. I know it's been ages since this question was live, but I just revisited it and realized there actually is a sort of clever way around this in this specific case. (You want a non-mutable NSArray from a C-style float array). You can create a custom subclass of NSArray that wraps the float values and only converts them to objects when they're accessed via the primitives. This may have performance pitfalls in some corners (?), but it does neatly meet your requirements:
#interface FloatProxyArray : NSArray
{
float * values;
NSUInteger count;
}
- (id)initWithCArray:(float *)arrayOfFloats count:(int)numberOfValues;
#end
.
#implementation FloatProxyArray
- (id)initWithCArray:(float *)arrayOfFloats count:(int)numberOfValues
{
if ((self = [super init])) {
values = (float *)malloc(numberOfValues * sizeof(float));
if (!values) {
[self release]; return nil;
}
memcpy(values, arrayOfFloats, numberOfValues * sizeof(float));
count = numberOfValues;
}
return self;
}
- (void)dealloc
{
free(values);
[super dealloc]
}
- (NSUInteger)count
{
return count;
}
- (id)objectAtIndex:(NSUInteger)index
{
if (index >= count) {
[NSException raise:NSRangeException format:#""];
return nil;
}
float val = values[index];
return [NSNumber numberWithFloat:val];
}
#end
(N.B. Written in the editor without compiling/testing.)
One optimization that you can do with the NSMutableArray is initWithCapacity which will prevent the doubling of your array which is the expensive operation in the addition.
Outside of that, since NSArrays and NSMutableArrays expect objects, so it's difficult to get around this.
What benefits of it being an NSArray are you looking to get?
It seems like you may be better off with a custom wrapper object around the C array that responds to whatever NSArray messages you are looking to call. Otherwise you are right back at the point of array creation... You could try manually creating a call to initWithObjects, but at the very least every float has to be wrapped in an NSNumber which would bring down your speed again.
If you really need an NSArray because something else you want to use takes NSArray objects, then you are probably better off subclassing NSArray (following the guidelines posted by Ben).
The “best” optimisation (for speed) would almost certainly be to avoid using NSArray altogether, if possible.