How to #synthesize a C-Style array of pointers? - c

I have a property defined in a class like so:
#interface myClass
UIImageView *drawImage[4];
...
#property (nonatomic, retain) UIImageView **drawImage;
...
#synthesize drawImage; // This fails to compile
I have found similar questions on StackOverflow and elsewhere, but none that really address this issue. What is the most Objective-C kosher way to do this?

You can't; you have to change that retain to assign and handle memory management yourself; as you can't send -[retain] to an UIImageView ** (as it isn't an object.)
That is to say; you can't actually use #synthesize as that would lead to epic memory leaks with assign and doesn't work with retain or copy; what you need to do is to implement -drawImage and -setDrawImage: and write some actually accessor code.
But don't do that. Use an NSArray.

The most "kosher" way would be to create an NSArray of UIImageView objects, instead of a C-style array.

A problem you'll encounter is that functions can't return C-style arrays in C or Objective-C, and another problem you might face is that you can't assign a pointer type to an array type (which is what your synthesised setter may be trying to do). There are at least two solutions:
Use an NSArray rather than a C-style array. This is the cleanest route, especially since you only have to manage the memory of one object rather than four.
Wrap the C-style array into a struct. You can't return C-style arrays straight from functions but you can return a struct that has an array member (be aware that there is no retain/release going on).
typedef struct {
UIImage *image[4];
} ImageCollection;
...
#property (nonatomic, assign) ImageCollection drawImage;
...
#synthesize drawImage;

Related

How to build an array of enums in Objective-C as NSNumber and then return these to enums again?

Having read several Q&As on this, it seems that the only way to build an array of predefined enums in Objective-C is to first convert to NSNumber. For example:
NSArray *fruits;
fruits = [NSArray arrayWithObjects:
[NSNumber numberWithInt:enumValue1],
[NSNumber numberWithInt:enumValue2],
[NSNumber numberWithInt:enumValue3],
nil];
This solved my first problem and allowed me to add enums to the array - and then shuffle (randomise) their indices, which was the whole point of building an array in the first place. However, is there any way of re-converting these NSNumbers back to their original enum form, effectively reversing the conversion, so that they can be evaluated against the original enum values?
The alternative, to also convert the comparator to an NSNumber at every evaluation, is at the very least ugly. In addition, I am getting some warnings during these evaluations, such as:
Comparison between pointer and integer ('ORKPredefinedTaskMovementOption' (aka 'enum ORKPredefinedTaskMovementOption') and 'NSNumber * _Nonnull')
Many thanks in advance!!

Check if an array exists Swift

In Objective-C I would write:
#property (nonatomic, strong) NSMutableArray *privateArray;
if (!self.privateArray) {
// Populate the privateArray
}
Which checks that an array does not already exists before populating it. How could this be achieved in Swift?
I have tried implementing it by translating my Obj-C code but am given an Xcode error "Unary operator '!' can not be applied to an operand of type '[AnyObject]'"
Swift attempt:
private var privateArray: [AnyObject]?
if !privateArray {
// Populate the array
}
How would I check if the array exists before populating the array, in Swift?
Is it just as simple to use .isEmpty on the array?
Thanks in advance!
In Objective-C this is called lazy loading. You declare a property but only create the property the first time it is accessed.
The trap you have fallen into is thinking that Swift is just a different syntax around Objective-C.
In Swift you can have a lazy var...
You can declare it like this...
#lazy var someArray: [String] = {
return ["Hello", "World"]
}
This will do what you want.
As a side note. It's generally not a good idea to use AnyObject especially if you know the type of object the array will contain.
Also, by using this method you don't need the array to be optional and so can avoid the whole unwrapping thing.
You can read more about lazy properties by googling it. I found this and it looks quite good... http://mikebuss.com/2014/06/22/lazy-initialization-swift/
You should write:
if (privateArray == nil) {
// Populate the array
}

How to decode rootObject

I have a custom class and I am trying to save an array within my class. In the encodeWithCoder method I use the encodeRootObject:theShotArray to save the data. What should I use for the initWithCoder method. There doesn't seem to be a decodeRootObject method. Is there a better way to save an array.
NSArray conforms to the NSCoding protocol, so you can say:
NSArray *rootArray = [[NSArray alloc] initWithCoder:myKeyedUnarchiver];
It may be a little confusing that NSArray's reference page doesn't specifically mention -initWithCoder:, but that's because that method is already described in the NSCoding protocol reference, and the NSArray reference page specifies NSCoding.

How to handle an array of pointers in Objective-C

I figured out the answer to this question, but I couldn't find the solution on here, so posting it for posterity.
So, in Objective-C, how do you create an object out of a pointer in order to store it in objective-c collections (NSArray, NSDictionary, NSSet, etc) without reverting to regular C?
NSValue *pointerObject = [NSValue valueWithPointer:aPointer];
This will wrap the pointer in an NSValue. To get it back out later use NSValue's instance method (pointerValue:)
An alternative solution is to define a class that has methods that access/manipulate the contents of the pointer, then add instances of that to the array.
Don't bother subclassing NSValue as it really adds nothing to the solution.
Something like:
#interface FooPtr:NSObject
{
void *foo;
}
+ fooPtrWithFoo: (void *) aFoo;
.... methods here ...
#end
I specifically chose an opaque (void *) as that tells the client "don't touch my innnards directly". In the implementation, do something like #define FOOPTR(foo) ((Foo *) foo) Then you can FOOPTR(foo)->bar; as needed in your various methods.
Doing it this way also makes it trivial to add Objective-C specific logic on top of the underlying datatype. Sorting is just a matter of implementing the right method. Hashing/Dictionary entries can now be hashed on foo's contents, etc...

Naming convention in Objective C /C , start with "_"?

Something I see ppl define the variable like this:
b2World *_world;
b2Body *_body;
CCSprite *_ball;
instead of
b2World *world;
b2Body *body;
CCSprite *ball;
I familiar with the second one, but not the first one. So, I checked the Wikipedia about naming convention:
Names beginning with double underscore
or an underscore and a capital letter
are reserved for implementation
(compiler, standard library) and
should not be used (e.g. __reserved or
_Reserved).
So, is that any special meaning which is start with "_"?
The code I saw which using "_" to begin is here:
http://www.raywenderlich.com/457/intro-to-box2d-with-cocos2d-tutorial-bouncing-balls
The wiki page.
There's a long-standing convention among some Objective-C developers to prefix instance variables with an underscore. It can be helpful in several ways: one, it makes it easier to spot instance variables in a .m file; two, it relieves developers of having to come up with creative names for method parameters to avoid colliding with instance variable names; and three, as others have noted, it indicates that the instance variables are private, and therefore shouldn't be accessed willy nilly throughout the code.
In fact, I'd argue for avoiding accessing instance variables directly in methods other than accessors (getters and setters), -dealloc, and -init.... Not that you should never, ever use them anywhere else, but you should at least give it some thought before using an instance variable directly in other methods.
It's really really helpful, but most people don't know why, and that's a shame.
Apple uses underscores to separate the way other objects access a particular object's variables, and the way a particular object access its own variables.
Now this may sound a little bit strange, but imagine the following: You probably all recognize the following compiler warning
.h
#property (nonatomic, retain, readonly) UITableView *tableView;
.m
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [self loadSomethingElseForTableView:tableView];
}
This will result in a compiler warning, because it does not know wether you reference to the local variable "tableView", or the instance variable.
Therefore, Apple recommends you to add the following to the top of your #implementation.
#synthesize tableView = _tableView;
Now, when you reference to _tableView, the compiler knows that you mean the instance variable, and not the local one.
Also, this makes it a lot easier to understand the Garbage Collection in Obj-C, and to prevent making common mistakes.
For example, when doing the following:
#property (nonatomic, retain, readonly) NSString *title;
- (id)initWithTitle:(NSString *)title {
if ((self = [super init])) {
self.title = title; // Is not possible, since it's read only.
title = title; // Is not possible, since it's the same (local) variable.
// Changing the method to initWithTitle:(NSString *)aTitle;
title = aTitle;
}
return self;
}
Now, since you do not use the default setter (actually, you can't, because it's read-only) you need to retain the variable yourself.
This is a lot easier to remember when you give every instance variable a prefix (so you know you need to retain it yourself).
So, basically, it's important to understand the difference between self.variable and (_)variable. (that is: self.variable maps to [self setVariable:...] and variable maps directly to your pointer.
Furthermore, when you add it as a private variable, like this:
#interface TSSomeObject : NSObject {
#private
NSString *_privateTitle;
}
#end
The underscore prefix isn't really necessary, unless you may encounter local variables that have the same name. Besides that, again, it's also an easy way to remind you that it's a local pointer and that you need to retain (and release) the variable when you assign it to your object.
What is wrong is to create a property with a underscore prefix, like this:
#property (nonatomic, retain) NSString *_title;
That's really wrong, and I'm not even gonna explain why ;)
So yes! You should really use underscore prefixes, it makes your code a lot easier to read, and to interpret by the compiler! In Xcode 4, Apple even added these #synthesizes to the default templates.
Usually they're used for variables that shouldn't be accessed outside the current file/module/namespace/whatever, in languages that don't support restricting access with something like a private keyword
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingIvarsAndTypes.html#//apple_ref/doc/uid/20001284-1001757
Both by convention and recommendation in the above document, you should prefix ivars with an underscore.
Admittedly, it is in reference to explicitly set ivars for properties.
But the usage is the same, to indicate the usage of an ivar wherever it is seen.
I am however open to the possibility, that in that context, the use of an underscore prefixed ivar could signal to the user that they are doing something wrong. Meanwhile a postfixed underscore could be used for pure ivars that are meant to be accessed directly.
This blog has some good thoughts from an experienced practitioner and it recommends using prefixed underscores.
http://blog.bignerdranch.com/463-a-motivation-for-ivar-decorations/
Wether you choose to use prefixed underscores to decorate your own ivars, there is at least some evidence that some kind of decoration will help you avoid bugs. And prefix'd underscores are the most common decoration.
Apple reserves names beginning with underscore for its own private ivars and methods. In Objective-C on any Apple platform, it is recommended that you do not prefix your identifiers with an underscore.
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingMethods.html

Resources