Obj-C introspection: how to avoid casting all the time? - objective-c

Hello all,
I've been working on some enumeration routines in Objective-C that perform object introspection. In particular, I'm fast enumerating an NSSet and making sure that the objects therein belong to class BBBallView (an fairly unfortunate name, I agree) before tweaking their properties and/or calling their methods.
In order to make the parser and compiler happy, however, I end up casting the object to its class on every single line; moreover, in order to access its properties, the object's cast has to be in parentheses, otherwise dot notation won't work. This leads to somewhat messy code:
for (id otherBall in self.gameField.subviews) {
if ([otherBall isKindOfClass:[BBBallView class]]) {
if ( !((BBBallView *)otherBall).isEnlarged ) {
CGRect otherFrame = ((BBBallView *)otherBall).frame;
/* ... */
}
}
}
Is there any way to tell the compiler something like "at this point I know that otherBall is a BBBallView, so stop telling me it doesn't respond to these selectors and properties"? That way, one could just write:
for (id otherBall in self.gameField.subviews) {
if ([otherBall isKindOfClass:[BBBallView class]]) {
if ( !otherBall.isEnlarged ) {
CGRect otherFrame = otherBall.frame;
/* ... */
}
}
}
and so on.
I tried otherBall = (BBBallView *)otherBall but "fast enumeration variables can't be modified in ARC by default". Changing the enumeration variable to __strong id fixes it, but doesn't help the fact that any subsequent line gives out errors such as "property isEnlarged not found on object of type 'const __strong id'", so I'm back to square one.
I'm not even sure why exactly this happens: shouldn't the compiler stay out of the way when an variable is of type id? In any case, the whole ordeal particularly messy in methods that need to perform several calculations on objects' properties, as it quickly becomes unreadable with all those parentheses.
Is there any way around this?
Thanks in advance!

You can either create a local temp with the correct type or just not use dot notation.
local temp
for (UIView *view in self.gameField.subviews) {
if ([view isKindOfClass:[BBBallView class]]) {
BBBallView *ballView = view;
if (!ballView.isEnlarged) {
CGRect otherFrame = ballView.frame;
/* ... */
}
}
}
don't use dot notation
for (id otherBall in self.gameField.subviews) {
if ([otherBall isKindOfClass:[BBBallView class]]) {
if ( ![otherBall isEnlarged]) {
CGRect otherFrame = [otherBall frame];
/* ... */
}
}
}
If I was only doing a couple of things I would be tempted to not use dot notation. If it became awkward to read and there was a lot of accesses then I would consider local temp

I think you're struggling because the logic appears misplaced. The language is fighting you because of your program's structure, not because the language is deficient.
Is the parent type of subviews really appropriate? Or are you violating the Liskov Substitution Principle by stuffing a round object in a square type?
You can also ask if is it really appropriate to examine the internals of BBBallView logic from outside? Can you move the logic into the appropriate class?

Related

Can a static variable used as #synchronized parameter?

We want to guarantee thread safety for a static variable.
We used another static variable as object in the #synchronized directive. Like this:
static NSString *_saveInProgressLock = #"SaveInProgressLock";
static BOOL _saveInProgress;
+ (BOOL)saveInProgress {
#synchronized(_saveInProgressLock) {
return _saveInProgress;
}
}
+ (void)setSaveInProgress:(BOOL)save {
#synchronized(_saveInProgressLock) {
_saveInProgress = save;
}
}
We are experiencing issues in the app currently on the store, which may be reproduced by preventing the _saveInProgress variable to be set to NO.
Do you see any problem with the above code?
How does it differ from this?
static BOOL _saveInProgress;
+ (BOOL)saveInProgress {
#synchronized([MyClass class]) {
return _saveInProgress;
}
}
+ (void)setSaveInProgress:(BOOL)save {
#synchronized([MyClass class]) {
_saveInProgress = save;
}
}
tl;dr: This is perfectly safe as long as the string literal is unique. If it is not unique there may be (benign) problems, but usually only in Release mode. There may be an easier way to implement this, though.
#synchronized blocks are implemented using the runtime functions objc_sync_enter and objc_sync_exit (source). These functions are implemented using a global (but objc-internal) side table of locks that is keyed by pointer values. On the C-API-level, you could also lock on (void *)42, or in fact any pointer value. It doesn't even matter wether the object is alive, because the pointer is never dereferenced. However, the objc compiler refuses to compile a #synchronized(obj) expression if the obj does not statically typecheck to an id type (of which NSString * is a subtype, so it's okay) and maybe it retains the object (I'm not sure about that), so you should only use it with objects.
There are two critical points to consider though:
if the obj on which you synchronize is the NULL-pointer (nil in Objective C), then objc_sync_enter and objc_sync_exit are no-ops, and this leads to the undesirable situation where the block is performed with absolutely no locking.
If you use the same string value for different #synchronized blocks, the compiler may be smart enough to map them to the same pointer address. Maybe the compiler does not do this now, but it is a perfectly valid optimization that Apple may introduce in the future. So you should make sure that you use unique names. If this happens, two different #synchronized blocks may accidentally use the same lock where the programmer wanted to use different locks. By the way, you can also use [NSObject new] as a lock object.
Synchronizing on a class object ([MyClass class]) is perfectly safe and okay too.
Now for the easier way. If you just have a single BOOL variable that you want to be atomic, you may use lock-free programming:
static BOOL _saveInProgress;
+ (BOOL)saveInProgress {
__sync_synchronize();
return _saveInProgress;
}
+ (void)setSaveInProgress:(BOOL)save {
_saveInProgress = save;
__sync_synchronize();
}
This has much better performance and is just as threadsafe. __sync_synchronize() is a memory barrier.
Note however, that the safety of both solutions depend on how you use them. If you have a save-method somewhere that looks like this:
+ (void)save { // line 21
if(![self saveInProgress]) { // line 22
[self setSaveInProgress:YES]; // line 23
// ... do stuff ...
[self setSaveInProgress:NO]; // line 40
}
}
that +save method is not threadsafe at all, because there is a race condition between line 22 and line 23. (Don't wanna go into details here.. just ask a new question if you need more information.)

Instantiating an object who's type depends on another object's type

As a part of my model I have a class called "Slide" which has two children : "QuizzSlide" and "ImageSlide". I also have another class called "SlideView" (which is part of my views) which has two children "QuizzSlideView" and "ImageSlideView".
Now what I want to do is go through a collection of Slides and create the correct SlideViews to display them. Problem is, to instantiate a SlideView I need to know the type of the Slide. QuizzSlide should create a QuizzSlideView and ImageSlide should create an ImageSlideView. I see two options :
Introspection. I don't like introspection because it means the class that builds the object has to exhaustively list the types of objects that it can deal with. If I add another type of Slides down the line, I have to modify the builder class.
Making the Slide create its associated View. So I'd have a function getView that gets overridden by every child of Slide to create the correct View for that slide. This would work and it would make maintenance easier but it makes a horrible mess of the program as the model shouldn't contain references to the views it represents.
That's pretty much it. Do I have any other options? Any ideas on how to uncouple my models from my views, build the correct views depending on the model types AND avoid introspection?
Thanks
Why not a Factory method createView() in the Slide class which, when implemented in QuizzSlide returns a QuizzSlideView and in ImageSlide returns an ImageSlideView pointing to the proper model.
This reminds me of the Iterator pattern, where CreateIterator() is the factory method.
Iterator pattern in UML http://www.silversoft.net/docs/dp/hires/Pictures/itera040.gif
I think the introspection method is best, however if you are concerned about having to modify the code if you introduce new classes (a legitimate concern) then I would make it table driven, which would limit the amount of new code required.
(Note I have not tested this code):
static struct {
Class slideClass;
Class viewClass;
} _slideMap[] = {
{ [QuizzSlide class], [QuizzView class] },
{ [ImageSlide class], [ImageView class] }
};
#define NUM_SLIDE_MAPS (sizeof(_slideMap) / sizeof(_slideMap[0]))
Then use:
for (id slide in _slides) {
UIView *view = nil;
CGRect frame = ...;
for (unsigned i = 0; i < NUM_SLIDE_MAPS && !view; i++)
if ([slide isKindofClass:_slideMap[i].slideClass])
view = [[_slideMap[i].viewClass alloc] initWithFrame:frame];
NSAssert(view, #"Missing slide/view map entry for class %#", NSStringFromClass([slide class]));
}
Note: It's possible this code won't compile as the expression [QuizzSlide class] is not a constant expression, in which case you will be forced to create the array at runtime, using a dispatch_once() statement or some such.
You might also be able to use an NSDictionary to hold the mapping between the slide and view classes and get even quicker look-up performance.

Design complexity with subclassing in Objective-C

I'm using Cocos2D for iOS, but you most likely don't have to be familiar with Cocos2D, just Obj-C to answer my question.
I have an enemy class while developing this game that I've used for a long time, but now it's reached a point of complexity and I'll need to do something about to make it more organized and readable.
The way it works currently is this: I have the enemy class that I allocate a certain number of times and insert into a mutable array. I can then flip through that mutable array whenever. When the enemy class is allocated, it is also directed to initialize and pass a string of the enemy name. In it's init there are a series of if/if else statements that check the enemy name and set the right values for it. This worked just fine, except design-wise it got very confusing to look through all those names when I added more and more enemies.
What I want to do now is subclass off of my enemy class of all the different enemies. I'll need to access the enemy's properties just like I would other kinds of enemies from that class.
Right now in the enemy class init I have something like:
-(id) initWithEnemy:(NSString *)kind {
if([kind isEqualToString:#"enemyName"]){
//set values
}
else if([kind isEqualToString:#"anotherEnemyName"]){
//set values
}
//etc, etc..
}
Now I want to have this set values stuff happen in other files. One, or a set of header/main files for each enemy. So inside initWithEnemy, I was thinking maybe I could allocate an enemy name class from the "kind" string that's passed. Not sure if I could use NSClassFromString. I've experimented with it a bit, but I'm not really sure how to access the class properties the way I did before. Even if I did access the properties the same way I did before, does that mean all the enemy name classes will have to have all the same amount of properties?
You can split your enemies into an abstract base class with concrete sub-classes - that is a good approach. Be mindful though, that it can often be better to use composition over inheritance - this is where you inject objects into a holder class to model something. Otherwise you might run into the problem where you have an enemy that's both a 'Monster' and a 'Wizard' and the single inheritance chain doesn't allow that.
There are two design patterns that seem appropriate here - they both focus on decoupling complex instantiation rules from the class itself. One is the factory pattern and the other is the builder pattern. If you split into a class hierarchy the former will be appropriate, otherwise the latter.
Sorry, can't provide more examples - writing this on an iPad, and on the way out the door.
Instead of strings, declare an enum
typedef enum {
kEnemyInvalid = 0,
kEnemyName1,
kEnemyName2,
[...]
} EnemyType;
Create an Enemy class with the global properties for all enemy types.
Create necessary enemy subclasses for each type. It's possible that a class will cover more than one enemy types.
Create a function (possibly a class method)
Class EnemyClassFromEnemyType(EnemyType type) {
switch (type) {
case kEnemyName1:
return [EnemyName1 class];
case kEnemyName2:
return [EnemyName2 class];
default:
return Nil;
}
}
This function makes a connection between the enemy type and the class that implements it. There are ways how to make it more pretty, my preferred way is using X-Macros.
And now let's create a factory method to create the enemies
+ (Enemy*)createEnemyWithType:(EnemyType*)enemyType {
Class enemyClass = EnemyClassFromEnemyType(enemyType);
return [[enemyClass alloc] initWithType:enemyType];
}
The same using X-Macros
Header file
#define ENEMY_DEFINITIONS \
ENEMY_DEFINITION(kEnemyInvalid, = 0, Nil) \
ENEMY_DEFINITION(kEnemyName1,, [EnemyName1 class]) \
ENEMY_DEFINITION(kEnemyName2,, [EnemyName2 class])
#define ENEMY_DEFINITION(name, intValue, enemyClass) name intValue,
/**
* Your enum declaration.
*/
typedef enum {
ENEMY_DEFINITIONS
} EnemyType;
#undef ENEMY_DEFINITION
Class EnemyClassFromEnemyType(EnemyType type);
NSString* NSStringFromEnemyType(EnemyType type);
Implementation file
#define ENEMY_DEFINITION(name, intValue, enemyClass) [name] = ##name,
NSString* EnemyTypeStringTable[] = {
ENEMY_DEFINITIONS
}
#undef ENEMY_DEFINITION
NSString* NSStringFromEnemyType(EnemyType type) {
return EnemyTypeStringTable[type]
}
#define ENEMY_DEFINITION(name, intValue, enemyClass) classTable[name] = enemyClass;
Class EnemyClassFromEnemyType(EnemyType type) {
static Class* classTable = nil;
if (classTable == nil) {
classTable = malloc(sizeof(Class) * sizeof(EnemyTypeStringTable) / sizeof(NSString*));
ENEMY_DEFINITIONS
}
return classTable[type];
}
#undef ENEMY_DEFINITION
The beauty of using X-Macros technique is that you have everything in one place, you can easily add more types without changing anything else. You get something like Java enums because the enums can have properties.

Help with Wikibooks WikiDraw Obj-C application

I decided to start learning some Obj-C. And I thought that Wikibooks wikidraw application would be a good place to start (after some very basic "Hello World" programs). I've followed the chapters and now I'm at the end of "WikiDraws view class". So now I'm supposed to be able to compile and run. Of course it dosen't work. I got a lot of errors at first but i have fixed most of them, only 6 remaining. This is one of them:
- (void) mouseDragged:(NSPoint) pt
{
NSPoint np;
np.x = pt.x - _anchor.x;
np.y = pt.y - _anchor.y;
if ( _dragState == 0) {
// dragging of object
[self offsetLocationByX:np.x byY:np.y];
}
else if ( _dragState >= 1 && _dragState < 9 )
{
// dragging a handle
NSRect nb = [self newBoundsFromBounds:[self bounds] forHandle:_dragState withDelta:np];
[self setBounds:nb];
}
}
- (NSRect) newBoundsFromBounds:(NSRect) old forHandle:(int) whichOne withDelta:(NSPoint) p
{
// figure out the desired bounds from the old one, the handle being dragged and the new point.
NSRect nb = old;
switch( whichOne )
{ ..........
So at
NSRect nb = [self newBoundsFromBounds:...
I get an error message, "Invailid initializer" and "WKDShape may not respond to '-newBoundsFromBounds:forHandle:withDelta:"- . What should I do? I'm new to coding but eager to learn.
/Carl-Philip
Assuming you've pasted that code in the order written in your source code and newBoundsFromBounds:forHandle:withDelta: isn't declared (as distinct from being defined) at some earlier point, I think the problem is just that at nb = [self newBoundsFromBounds:... the compiler doesn't yet know what the return type will be. An NSRect is a C-style struct rather than an Objective-C class, so the compiler really does need to know.
As a solution, either put the definition of newBoundsFromBounds:... before mouseDragged:, add it to the #interface in your header file if you want it to be exposed to everyone or declare it internally to the implementation file as a category method. To do the final one, add the following to the top of your .m, assuming your class is called WikiDrawsView:
#interface WikiDrawsView (private)
- (NSRect)newBoundsFromBounds:(NSRect) old
forHandle:(int) whichOne
withDelta:(NSPoint) p;
#end
The 'private' is just a name you get to pick, it has no special meaning. Something like 'private' is often used to signify that you're using a category in a similar way that you might use private class member functions in C++ or a language like that.
The quick way to describe categories is that they patch additional methods onto existing classes at runtime, and they use the #interface [classname] ([category name]) syntax, with no member variable section. I'm sure your tutorial will get to them, Apple's documentation on them is here. This is a common use of categories but not the primary use.
To address the "WKDShape may not respond" warning, make sure you declare -newBoundsFromBounds:forHandle:withDelta: before -mouseDragged:. You can add it to the public interface in "WKDShape.h", or in an anonymous category in "WKDShape.m".

What does "Context" mean in Cocoa/Objective-c?

Recently I've been seeing the word "context" used in method names in Cocoa, but I don't understand the meaning. I've seen it in places like Core Data (NSManagedObjectContext) and in Core Graphics (CGBitmapContextCreate) but it seems to be used all over (NSSet, NSArray, NSObject). I'm assuming that it comes from the c world.
What is this context they're talking about?
It's just terminology, the contexts you mention are unrelated. The word context is usually used to describe a particular "working space".
For example, a CGContextRef or NSGraphicsContext stores a graphics space that you can perform drawing operations in.
NSManagedObjectContext stores a "working set" of NSManagedObjects for a particular persistent store.
The documentation for each API describes in detail what each of these contexts are.
There is no particular meaning, but there are two common ones.
First one is connected with databases, persistence layers, graphics and such beasts where you need some notion of a ‘scope’, ‘connection’ or a ‘state’. For example when saving data into a database you usually need to open the database and then save some DB ‘handle’ you will refer to in subsequent operations. There can be many different connections and thus many different ‘handles’. In other words there can be many DB contexts. Same goes for OpenGL.
Context is also used a lot in the various callback and selector passing APIs. Here it’s simply some chunk of data you would like to receive when the callback happens or the selector gets excuted. The usual use case for this is when you subscribe several times and need to tell these occasions apart:
// In one part of code not far away.
[anObject subscribeToEvent:NSObjectEventFoo withContext:#"one"];
// Somewhere else.
[anObject subscribeToEvent:NSObjectEventFoo withContext:#"two"];
// And when the callback happens:
- (void) eventFooHappenedInContext: (id) context
{
if ([context isEqual:#"one"]) { /* something */ }
if ([context isEqual:#"two"]) { /* something else */ }
}
The context is also used in the sorting APIs, like in the NSArray you mentioned. If you for example wanted to sort the objects according to some weight stored in a NSDictionary you could use the context to pass the weights:
NSInteger weightSort(id obj1, id obj2, void *context)
{
NSDictionary weights = (NSDictionary*) context;
const int weight1 = [[weights objectForKey:obj1] intValue];
const int weight2 = [[weights objectForKey:obj2] intValue];
if (weight1 < weight2)
return NSOrderedAscending;
else if (weight1 > weight2)
return NSOrderedDescending;
else
return NSOrderedSame;
}
(This is a bit contrived, but I think you get the point.)
I found it interesting that the context is a lot of times simply a poor man’s solution to closures that are/were missing in the language. Because with closures you could simply pass a separate callback handler, like in JavaScript:
anObject.subscribeToEvent(eventFoo, function() { /* do something */ });
anObject.subscribeToEvent(eventFoo, function() { /* do something else */ });
This would be often more elegant than differentiating the use cases in the callback. It is now possible to do something like this in Objective-C with blocks (see tutorial by Mike Ash).