Is this a safe/valid hash method implementation? - objective-c

I have a set of classes to represent some objects loaded from a database. There are a couple variations of these objects, so I have a common base class and two subclasses to represent the differences. One of the key fields they have in common is an id field.
Unfortunately, the id of an object is not unique across all variations, but within a single variation. What I mean is, a single object of type A could have an id between, say, 0 and 1,000,000. An object of type B could have an id between, 25,000 and 1,025,000. This means there's some overlap of id numbers. The objects are just variations of the same kind of thing, though, so I want to think of them as such in my code. (They were assigned ids from different sets for legacy reasons.)
So I have classes like this:
#class BaseClass
#class TypeAClass : BaseClass
#class TypeBClass : BaseClass
BaseClass has a method (NSNumber *)objectId. However instances of TypeA and TypeB could have overlapping ids as discussed above, so when it comes to equality and putting these into sets, I cannot just use the id alone to check it.
The unique key of these instances is, essentially, (class + objectId). So I figured that I could do this by making the following hash function on the BaseClass:
-(NSUInteger)hash
{
return (NSUInteger)[self class] ^ [self.objectId hash];
}
I also implemented isEqual like so:
- (BOOL)isEqual:(id)object
{
return (self == object) || ([object class] == [self class] && [self.objectId isEqual:[object objectId]]);
}
This seems to be working, but I guess I'm just asking here to make sure I'm not overlooking something - especially with the generation of the hash by using the class pointer in that way. Is this safe or is there a better way to do this?

This is probably safe, but not necessarily. Depending on strict class identity can bite you if you actually wind up with a subclass somehow (e.g. if KVO causes your class to be switched for another*). It would probably be a little bit safer if use some sort of explicit class ID.
Also keep in mind that unequal objects do not need to have different hashes. The only requirement is that objects that are equal must have the same hash. So it's OK if objects in the two classes have the same hash as long as this doesn't wind up slowing your hash tables too much.
(*I honestly don't remember off the top of my head if the secret KVO subclass masquerades as the parent class, in which case you'd still be safe here, but I generally try to avoid depending on class identity.)

Related

How to use NSCache with multiple pieces of information that together act as a 'key'?

I'm trying to understand the concept of NSCache, and one thing that strikes me is that a NSCache instance does not guarantee to give back the value to a key you stored before. It might not even store the key value pair when you try to add it, if it deems that the performance is more important at the moment.
What that implies, for me, is that:
Each key must 'hold' enough information to generate the value if necessary
Each query for the NSCache, which essentially is just in the form of a key, should thus wrap up all the information needed to generate the corresponding value.
From the above two points one can say that NSCache serves no purpose of establishing any kind of association between a key and a value - the user must be able to generate the value independent of the cache, and the sole purpose of using a NSCache is not to 'look up' some value, but rather just to trade memory for some performance boost
So my problem is about storing transparency masks for images. Initially I thought I just need to use the names of the images as the keys, but from my deductions above it seems that's not sufficient - I also have to include all other parameters used in generating a mask e.g. the transparency threshold, for example. It also means that every time I ask the cache for a mask I have to provide ALL the parameters. And the only way that I can think of about doing that is to use something like NSInvocation as the key; but that seems a rather clunky solution.
It is the very nature of a cache to be volatile, so caches should only ever be used to speed up access to information that could also be acquired some other way.
Your idea to create keys that hold all this information should work - just remember to store all your keys somewhere other than the cache as well.
As for the key, you can create a very simple class that has nothing but a couple of properties (the ones that make up a key), an isEqual: and hash method and maybe an initializer that takes parameters for each of your properties.
This requires extremely little code, since accessors and iVars for properties are autogenerated, so the only thing you really need to write is the isEqual: method (and hash).
This class is so small and taylor-made for the particular case you need it for, it makes sense to declare and implement it at the top of the .m file you're going to use it in. This way, you don't pollute the rest of the system. Just add #interface and #implementation sections for your class at the top of your .m file.
After more thought about this I think I've got one thing wrong - the keys in a NSCache do not necessarily need to hold all the information for generating the values. A key in a NSCache can serve the same purpose as that in a NSDictionary - a unique identifier to look up the value. The only difference, though, is that you'd always need to have a backup plan B for a NSCache in case the key-value pair added before is destroyed.
In simplier terms, operations on the two different classes look like this:
NSDictionary
generate each value V for each key K and add the pairs to the dictionary
look up V using K
NSCache
look up V using K
if V == nil, generate the value V and add the pair to the cache
Therefore it's possible to convert almost any NSDictionary to a NSCache, only that after the conversion you can't pass the NSCache around - you have to know how to generate the values at all times and thus the NSCache instance would most probably be a private property used exclusively in a certain class.
For my problem I've resolved to use a method like this (self is supposedly pointing to a subclass of NSCache, but I haven't tested it yet)
- (Mask *) maskForImageName:(NSString *)name maskGenerator:(Mask *(^)(NSString *))generator {
Mask *mask = [self objectForKey:name];
if (!mask) {
mask = generator(name);
[self setObject:mask forKey:name];
}
return mask;
}
It would be further simplified if objective-c is a functional, lazy-style language, in which case I don't even need to wrap the generator in a block; but I'm satisfied with this solution for now. In fact I feel that this pattern is almost always used with NSCache so I'd just add it as a category to NSCache.

Objective C Helper Methods

Novice here attempting to understand inheritance. If I initialize a new object with several properties and I want other classes to help assign values to those properties, do I need to create instances of those other classes? Visualized:
-(ObjA *)init{
self = [super init];
self.property1 = [method from Class A];
self.property2 = [method from Class B];
self.property3 = [method from Class C]; etc...
return self;
}
In other words, assuming Class A, B, and C need to know what Object A is, would I need to make those class methods instance methods and initialize each object? Is there another way to go about this? Thank you in advance for your help.
In other words, assuming Class A, B, and C need to know what Object A
is
NO.
You can simply call a method from ClassA/B/C etc. But the return type must match with respective property.
Let, the property1 is for kind NSString then your ClassA method must be
-(NSString *)methodClassA{
...
return someStringValue;
}
Then you need to use:
ClassA *objClassA=[ClassA new];
self.property1=[objClassA methodClassA];
Or you can go with class method by this:
+(NSString *)methodClassA{
...
return someStringValue;
}
And using it as:
self.property1=[ClassA methodClassA];
assuming Class A, B, and C need to know what Object A is
The initialization code of an object should be self contained, unless it is using functionality owned by a different object, in which case the object acts as a client of that functionality. That is, objectA acts as client of A,B,C (as seen in your code).
But this doesn't imply that A,B,C need to know (have a dependency on) objectA. By doing that, you are saying that they don't have a reason to exist on their own.
In general,
Every class or method should have one encapsulated purpose. This makes it easy to understand, change, and test in isolation. It's a common pattern to create classes whose sole purpose is to encapsulate information to create a different class, but to split that in three different classes is beyond weird (as in, I can't imagine an example of that).
An object shouldn't be allowed to exist in an unusable state, nor should it require non essential information when it is created. Does objectA require those properties to function? if it does, your code is right, if it doesn't, the initializer is providing too much information and making it less reusable.
Try to rethink your doubt with a real (instead abstract) example. You may end up making sense of it yourself.

"Decorate" several classes with a specific method in Obj-C

I'm not yet that into design patterns so "Sorry!" to bother you with such a question, that might be obvious.
The thing is, I have several classes: Show, Segment, Command. These three classes are totally different, except the one thing: They all have an NSArray called schedules, which contains ScheduleItem classes.
In my workflow I need to check, if the current time matches a scheduleItem to set the Show,Segment or Command active. So, I'd like to have a method on all these three classes called isActive(). Since this method does the same for all current and future classes, I'm looking for a way to implement the isActive method just once, and reuse it in those classes.
Is there a nice way doing this?
To remember, those classes have absolutely nothing in common, except the schedules array. So, I'd like to avoid subclassing. But you can convince me otherwise.
You can create smth like this
#interface ScheduleCollection : NSObject {
NSArray* schedules;
}
#property NSArray* schedules;
/**
Return true if matches.
*/
-(BOOL) match:(ScheduleSclass); //or call it isActive or whatever you like
#end
Then replace schedules array in Show, Segment, Command with ivar of this class. If you need to compare time just get the property and call match:
Show* show = ...;
BOOL m = [show.schedules match: my_time];
There's really no design pattern for this except generic inheritance (shared base class with the method). You can't add it as a category for all three, as they don't share a base class.
If you want to avoid introducing a base class, you can use the fact that type id is a typeless object, and you can invoke any method on it at runtime. Only it will fail if the actual objec doesn't have the method...
On each of the objects, create a method called getSchedule like this:
- (NSArray*) getSchedule {
return schedule;
}
Then just create this method somewhere else
-(BOOL) isActive:(id)anyObjectWithGetScheduleAnyOtherWillFailWithSelectorNotImplemented
{
// You could do an explicit check to determine if the object passed in implements
// getSchedule, but I skipped it here.
NSArray* schedule = [anyObjectWithGetScheduleAnyOtherWillFailWithSelectorNotImplemented getSchedule];
<your implementation here>
}
In my opinion, you would be better off just introducing a shared base class, as it's a lot clearer and won't really take that much more work. But if you have good reasons not to, this will also do the job.

Implementing a category within the implementation of another interface in Obj-C

I have a custom class in Obj-C called RouteManager which contains an array of NSStrings. Each string is a bus stop name which is used as a key for a dictionary to get the rest of the information for the bus stop (basically, just [busStopDictionary allkeys]). In one of the situations where my app uses this array, I want to return the array sorted by the distance from the user. I've started setting up the code to be able to call sortedArrayUsingSelector on my array with the following method:
- (NSComparisonResult)compareByDistance:(NSString*) otherStop
{
// Return appropriate NSOrdered enum here based on comparison of
// self and otherStop
}
My problem is that in the case where compareByDistance is a method of RouteManager, self refers to the instance of RouteManager. However, I need self to refer to the NSString that the compare is being called on. So, I assumed I needed to setup a category, as such:
#interface NSString (Support)
-(NSComparisonResult) compareByDistance:(NSString*)otherStop;
#end
This got my self reference correct, however this comparison uses values from the RouteManager class. When implemented as seen above, the NSString (Support) implementation obviously complains that those values are undeclared.
That should provide enough background info for my question. How do I go about doing this? I would like my category of NSString, which consists solely of the method compareByDistance, to be able to use values from the current instance of my class, RouteManager, which inherits from NSObject. Ideally, I feel as though the category should somehow be within RouteManager. I feel there has to be some way to accomplish this that is cleaner than passing the necessary values into compareByDistance. Thanks in advance for any and all help.
Your best bet would be to define a custom class for a bus stop, instead of storing them as strings and dictionaries.
Make the BusStop class have properties for Name, Location and whatever else. Implement the compareByDistance: method on the BusStop class.
You can still use a dictionary if you need to look them up by name. Just store them with the name as the dictionary's key, and the BusStop object as the dictionary's value.

Java-enum style classes in Objective-C?

I am new to Obj-C so forgive me if this is a stupid question:
How do I implement some in the style of Javas enums? Or to be more precise:
I want a class with some known properties which are fix at compile time and unique per instance. Additionally I only want one instance type.
Let me give an example in Java:
public enum MessageTypes {
DEFAULT("white", "standard", 1),
EXPRESS("red", "expressMessage", 2),
BORADCAST("green", "broadcast", 3);
String color; String tagName; int dbId;
MessageTypes(String color, String tagName, int dbId) {
// you get the idea
}
//some methonds like getEnumByTagName
}
How would you do something like this in Objective-C? Am I missing something? Is this a bad pattern at all?
Thanks in advance!
EDIT: I am sorry, if I did not made myself clear. I know, that obj-c enums are not what I am looking for (as they are only marginally more than a typedef to an int).
I would like to create a set of (kind-of-singleton, immutable) instances of a specific class. The singleton pattern in Apples Dev-Docs is of no use as I want multiple distinct instances of a class each with individual values in their properties.
The goal of that is to have multiple Message types (about 20) that can be assigned to a Message as a property. Each of my Message types has a (fix and predefined) color, attribute-value (in an XML-representation) and a numerical ID.
In Java, I would use an enum as in my code sample. But how do I create different MessageTypes and associate them with their properties in Obj-C?
Creating 20 Sublcasses of MessageType (each with a singleton-instance holding the properties) seems like a lot of work for such a simple task and total overkill.
My current approach is to create a class with an NSArray holding the different instances. Up on first access of a method like +(id)messageTypeForId:NSInteger id_ the NSArray is prepopulated. But this feels totally clumsy and not at all elegant...
Is there a more satisfying approach?
There is not much in the way of a "more satisfying approach".
The normal Cocoa pattern would be to create methods like:
+ (MessageTypes*) sharedDefaultMessageType;
+ (MessageTypes*) sharedExpressMessageType;
+ (MessageTypes*) sharedBroadcastMessageType;
etc
and then implement them something like:
+ (MessageTypes*) sharedDefaultMessageType
{
static MessageTypes* thisMessageType = nil;
if ( !thisMessageType ) {
thisMessageType = [[MessageTypes alloc] initWithColor:#"white" tagName:#"standard" dbId:1];
}
return thisMessageType;
}
Alternatively, storing the shared MessageType* in an NSMutableArray or NSMutableDictionary or precalculating them as you are doing are all equally valid approraches.
Note that the above "template" method could be generated via a macro such that you could write in the .m file:
CREATEMESSAGETYPE( Default, #"white", #"standard", 1 )
CREATEMESSAGETYPE( Express, #"red", #"expressMessage", 2 )
CREATEMESSAGETYPE( Broadcast, #"green", #"broadcast", 3 )
which might be "more satisfying" or more ugly, depending on your point of view.
I think I'd just use a standard C enum:
typedef enum { MT_WHITE, MT_RED, MT_GREEN } MessageType;
Then you just use it as you would any other data type:
#interface Blah {}
-(void) setMessageType:(MessageType)newMessageType;
#end
Enums are not objects in C, and thus not in Objective-C either. They're just user-defined scalars that have a limited set of named values that they can take. You can give an object properties that are enum types, which I think is closest to what you're looking for.
If there's something specific you need to accomplish with this functionality, you might want to edit your post to indicate what that is.
I had the same question more or less but find all the above solutions clumsy stylistically.
In particular when simply using a C enum property on an object you lose the singleton semantics of Java enums. The biggest freedom I have found in the use of Java enums is that the instances of an enum are really singleton subclasses, and so participate in method polymorphism. Even more powerful than enums with unique attributes is enums with polymorphic behaviour.
Given that this is the key feature I am after would an Objective-C class cluster with singleton private subclasses be an approach with the desired behaviour, despite being a bit over the top in implementation cost and complexity?