ObjectiveC: convention to define reusable identifier - objective-c

I'm pretty new to Objective-C and trying to figure out what is the accepted convention to define a reusable identifier for either collection / table view cell.
In Swift, I've seen something like
class SomeCell: UITableViewCell {
static let identifier = "SomeCell"
// ... other
}
How do Objective-C developers deal with this?

Related

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.

Create a subclass of a class using parent's init - from another class

Edit: This downvoting syndrom here sucks big time. I asked a question where I in my opinion showed that I did my homework, and asked for advice. The upvoted answers implied going with compile time warnings, whereas my own and probably most clean OOP way didn't receive any interest.
Brief overview in order to understand why I need this and what I try to do: I'm writing an ORM that implements the data mapper pattern. A mapper (i.e. for SQLite results) must create subclasses of an entity class - using the initializer of the base entity class. So there is the problem.
The mapper does not, and should not, know about specific classes. Mapping descriptions and specific mappers for different data sources are abstracted away from the entity class, and by design part of the entity description.
Entities are similar to NSManagedObject, though the ORM follows a different pattern. The description any entity is created with is similar to NSEntityDescription (but also following a different pattern and purpose).
So my goal is to create entities that I know are subclasses of ManagedEntity, using the init method of ManagedEntity.
So the init of my mapper looks like this:
- (id)initWithEntityClass:(Class)EntityClass entityDescriptor:(EntityDescription*)entityDescriptor
{
self = [super init];
if (self)
{
_EntityClass = EntityClass;
_entityDescription = entityDescription;
... (assert that class is of subclass of ManagedEntity)
}
And some time later in my mapper I then want to create the concrete entity:
-(void)createEntityWithSQLiteResultSet:(sqlite3_stmt*)resultSet
{
// Problem: How to init a class known to be a subclass of ManagedEntity?
ManagedEntity *newEntity = [[_EntityClass] alloc] initWithEntityDescription:_entityDescription];
}
So how do I create this child class of ManagedEntity, using the init of ManagedEntity?
Sure, I could use respondsToSelector() for initWithEntityDescription and invoke that. But something tells me there should be a more elegant way where the class kind is already known. Also, respondsToSelector and selector invocation will do a runtime check only. Even though the entity initializer should not change, it seems a bad choice to lose compile time checking if this method exists.
As part of your mapping, you must know what subclass you need. Then use
ManagedEntity *newEntity = [[NSClassFromString(className) alloc] initWithEntityDescription:_entityDescription];
EDIT:
I was building out this in a GitHub project as I promised and realized why it may not compile. You must have -initWithEntityDescription: declared in a known class that is accessible within the scope. In this case, it would mean that you must declare and implement ManagedEntity -initWithEntityDescription: and have have `#import "ManagedEntity.h" at the top of your file.
To reinforce Neal's correct answer that the OP claims cant work because he knows objC :)
#import <CoreData/CoreData.h>
#interface TestMapper : NSObject
- (NSManagedObject*)createClassForEntity:(NSEntityDescription*)entity context:(NSManagedObjectContext*)ctx;
#end
#import "TestMapper.h"
#implementation TestMapper
- (NSDictionary*)entityToClassMap {
return nil; //TODO ;)
}
- (NSManagedObject*)createClassForEntity:(NSEntityDescription*)entity context:(NSManagedObjectContext*)ctx {
NSString *className = self.entityToClassMap[entity.name];
assert(className);
return [[NSClassFromString(className) alloc] initWithEntity:entity insertIntoManagedObjectContext:ctx];
}
#end
alternative using the runtime you want
id cls = NSClassFromString(className);
id alloced_cls = objc_msgSend(cls, #selector(alloc));
id newEntity = objc_msgSend(alloced_cls, #selector(initWithEntity:insertIntoManagedObjectContext:), entity, ctx);
return newEntity;

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.

What is the recommended method of styling an iOS app?

What is the recommended method of styling an iOS app? For example, if there are multiple labels or text views how can updating font style/color at one place update the style/color at all other places?
I know sub classing could be one way... is there any other way?
You could import a standard header file into all your controllers with several constants set for styling... example:
Styles.h
#define kFontSize 14
#define kFontFamily #"Helevetica"
Controller
#import "Styles.h" // at the top
myLabel.font = [UIFont fontWithName:kFontFamily size:kFontSize];
I personally think Interface Builder is the best way to style, however this answers your question directly.
Update: I would recommend starting by understanding UIAppearance APIs, and seeing how well they suit your needs. UIAppearance is a convenient way to provide custom default stylization of specific controls' attributes at multiple levels (e.g. globally or contextually).
My original answer, which predated UIAppearance's availability:
since we're working with an object based language...
for the implementation, it depends on how you want it to behave/execute. when the implementation becomes nontrivial, i will often create a protocol. you could use class methods or instance methods and significantly optimize these types for your usage because you create fewer intermediate colors, fonts, images, etc.
a basic interface could take the form:
#protocol MONLabelThemeProtocol
- (UIFont *)labelFont;
- (UIColor *)labelTextColor;
- (UITextAlignment)labelTextAlignment;
// ...
#end
#protocol MONTableViewCellThemeProtocol
- (UIFont *)tableViewCellFont;
- (UIColor *)tableViewCellTextColor;
- (UIImage *)tableViewCellImage;
- (NSInteger)tableViewCellIndentationLevel;
- (CGFloat)tableViewCellIndentationWidth;
// ...
#end
then a simple amalgamate theme could be declared like this:
#interface MONAmalgamateThemeBase : NSObject
< MONLabelThemeProtocol, MONTableViewCellThemeProtocol >
{
#protected
/* labels */
UIFont * labelFont;
UIColor * labelTextColor;
UITextAlignment labelTextAlignment;
// ...
/* table view cells */
UIFont * tableViewCellFont;
UIColor * tableViewCellTextColor;
UIImage * tableViewCellImage;
NSInteger tableViewCellIndentationLevel;
CGWidth tableViewCellIndentationWidth;
// ...
}
#end
in this example, the amalgamate defines the getters and dealloc and expects the subclasses to initialize the instance variables. you could also support lazy initialization if initialization times are high (e.g. uses many images).
then a specialization could take the form:
#interface MONDarkTheme : MONAmalgamateThemeBase
#end
#implementation MONDarkTheme
- (id)init
{
self = [super init];
if (nil != self) {
labelFont = [[UIFont boldSystemFontOfSize:15] retain];
labelTextColor = [[UIColor redColor] retain];
// and so on...
}
return self;
}
// ...
#end
/* declare another theme and set it up appropriately */
#interface MONLightTheme : MONAmalgamateThemeBase
#end
then just reuse the theme instances (e.g. MONDarkTheme) throughout the app to stylize the views. if you have a lot of themes or they are not trivial to construct, then you may want to create a collection for themes (theme manager). the amalgamate could also take a parameter, such as init with theme if your needs are simple. you can even configure objects to register for changes to themes, if you need support for dynamic changes.
finally, you can create a simple theme applier to make life easier - like so:
#interface UILabel (MONThemeAdditions)
- (void)mon_applyMONLabelTheme:(id<MONLabelTheme>)theme;
#end
#implementation UILabel (MONThemeAdditions)
- (void)mon_applyMONLabelTheme:(id<MONLabelTheme>)theme
{
assert(theme);
if (nil == theme) return;
self.font = [theme labelFont];
self.textColor = [theme labelTextColor];
self.textAlignment = [theme labelTextAlignment];
}
#end
Frankly, the best way to go about this is to use Interface Builder. While it might seem nice to change a single constant somewhere in the code and have the entire app change styles, it never quite works out that way. Here are my reasonings:
1) Developers don't write interface code as well as interface builder does.
Interface builder is a tool that has been refined, tested, and intreated over years. It offers fonts, text alignment, shadow, etc. It is backwards compatible for as far back as you'd ever want. It provides a very simple way for any number of developers and designers to jump in and work on something very straightforward.
2) There are always edge cases that you'll have to account for. Sure, a simple constant will do what you want most the time, but you'll eventually have to hack something in here and sneak something in there. The "simple" interface code you wrote to start off will grow and grow and grow. Other developers will have to maintain that code. You will have to maintain that code. You will have to file and fix bugs, tweak this, except that, etc. It will inevitably become a steaming pile of mess.
3) The more code you write, the more bugs you write. Interface builder is for building the 'look' of most iOS apps. Use it. Don't get too clever.
NOTE:
I understand that Interface builder cannot do everything for all apps. There are cases that coding an interface is the only solution. This answer is simply a general "best practice" I use in the bulk of my apps.
Similar to Alex's idea, you could create a static class called ThemeManager:
typedef enum
{
defaultStyle,
redStyle,
} ThemeStyles;
#interface Level : NSObject
{
ThemeStyles currentTheme;
}
All classes which can be themed will import ThemeManager. Then, you can create methods like:
+ (UIColor*) fontColor;
Which other classes would call when they want a color for their font. Then, if you want to change themes, you could implement fontColor as:
+ (UIColor*) fontColor
{
switch (currentTheme)
{
case defaultStyle:
return [UIColor blackColor];
case redStyle:
return [UIColor redColor];
}
}
When you want to change the theme, you could have ThemeManager implement a method like:
+ (void) changeTheme:(ThemeStyles)newTheme
{
currentTheme = newTheme;
}
You can use a third-party abstraction of UIAppearance:
NUI: https://github.com/tombenner/nui
Pixate: http://www.pixate.com
Using a Storyboard has a lot of benefits, but many style options aren't available, not the least of which is custom fonts. If you want a deeply-customized UI, you will need some style code to make it happen.
I use plists. Just as I localize strings, I use the same procedure to change themes. I coded a singleton that loads a current theme plist and a fallback plist. Then I replace the names of resources with keys and macro functions that pull the real resource name from the singleton.
Cons: you have to set the resource for each element, not just set it in the NIB.
Pros: once you are done, most of the next theme involves photoshop and textmate, not IB or code.
You may need to look at this library. It supports multiple themes/skins on the fly. Supports images and colors currently. Font support will be added in future.
https://github.com/charithnidarsha/MultiThemeManager

How to base class behaviors on typedef enums, the way Apple does in Objective-C?

Kind of a weird newbie question...I want to use typedef enum declarations in one of my classes . This particular class gets used by other classes, where a client class might say something like "set your style to Style1 (enumerated type)". Then the target class's behavior would change accordingly. This is analogous to the way that UITableViewCellStyles are used in the iPhone SDK.
So, I read through a few UIKit framework headers to get a better idea of how Apple was handling the enumerated types. I see that they declare a bunch of enums everywhere, like so...
typedef enum {
UIBarButtonSystemItemDone,
UIBarButtonSystemItemCancel,
UIBarButtonSystemItemEdit,
UIBarButtonSystemItemSave,
UIBarButtonSystemItemAdd,
...
UIBarButtonSystemItemUndo, // available in iPhone 3.0
UIBarButtonSystemItemRedo, // available in iPhone 3.0
} UIBarButtonSystemItem;
...but I don't see any clues in the header on how they actually handle these types (I'm basically trying to see an example of their implementation, so this isn't a suprise). My instinctive thought as a fairly newb programmer would be to match the int values of each type to some behavior/variable stored in an array, plist etc. But also as a newb programmer I expect that everything that I think will be wrong. So I have two questions:
Anybody have a guess as to how Apple itself handles enum type values to change behaviors?
In general for this type of setup, is there a best design practice that everyone knows about or is this just an open-ended scenario?
Simple enums are usually handled in a switch statement:
typedef enum {
eRedStyle,
eGreenStyle,
eBlueStyle
} MyStyle;
#implementation MyClass
- (void)setStyle:(MyStyle)style {
switch (style) {
case eRedStyle :
self.backgroundColor = [UIColor redColor];
break;
case eGreenStyle :
self.backgroundColor = [UIColor greenColor];
break;
case eBlueStyle :
self.backgroundColor = [UIColor blueColor];
break;
default :
NSLog(#"Bad Style: %d", style);
break;
}
}
An enumeration is (almost but not really) an integer, but made easy to read for the programmer that's using it. Given that, you can have routines that check the value of an enum the same way you would an integer:
void DoMyEnumeratedThing(UIBarButtonSystemItem item)
{
if (item == UIBarButtonSystemItemDone)
DoMyItemDoneThing();
else if (item == UIBarButtonSystemItemCancel)
DoMyItemCancelThing();
// ...and so forth and so on.
}
While I don't know the gory details of Apple's OS internals, every enumeration check essentially boils down to something like the above. As for your "best design practice" question, the answer really depends on what you're trying to accomplish with the enumeration. While every use-case is switch-like, sometimes the enumeration is a set of bits in a bitfield that allow the client to toggle one or more of them at the same time (which is not the case in the example you provide).