質問

I'm writing a class in Objective C that has an ivar with instances of the same class...

@interface State : NSObject {
NSString *name
NSSet *neighboringStates    // this is a set of State objects
}

State *california would have *neighboringStates containing *oregon, *washington, and *nevada. Each of those three States have among their neighboringStates *california.

I want the pointers to refer to the same instances, so that each state is instantiated only once, and any changes to the state during a method call in another state would affect the same object in memory.

Does this work? I'm not even sure what the term for this is, so it's hard to google it.

I appreciate your help!

EDIT:

To give you more clarity on what I'm trying to do, I'd like to generate permutations of states such that each state is visited only once and each next state in the permuted list must be from a neighboring/adjacent state to the current one. So that once I start in california and travel to oregon, since I know my current path contains california, I remove california from my available states. I keep track of available states by taking the neighboringStates set of the current state and removing any states that are in my current path.

役に立ちましたか?

解決

I’m not sure what exactly your question is. There’s a design pattern called Singleton that ensures that you can only have one instance of a given class. This is not exactly what you want, but there’s a variant of the Singleton pattern called Multiton that keeps a single instance of the class for given key (in your case, a state name). This is how [NSNull null] (a singleton) or NSNumber (multiton) work:

NSLog(@"%i", [NSNull null] == [NSNull null]); // 1
NSLog(@"%i", [NSNumber numberWithInt:42] == [NSNumber numberWithInt:42]); // 1

But these patterns are very easy to misuse and it would probably be much better if you could solve the problem without them. There’s no problem in making all the state pointers refer to the same instance. That is, there’s just the problem of creating the whole object graph. That’s easy if you keep the properties mutable:

State *oregon = [[State alloc] initWithName:@"Oregon"];
State *washington = [[State alloc] initWithName:@"Washington"];
[oregon setNeighbouringStates:[NSSet setWithObject:washington]];
[washington setNeighbouringStates:[NSSet setWithObject:oregon]];

And so on. An even better solution to your problem might be a different data model, different way to represent the neighbouring relation. But that depends on your requirements.

You say in the comments that you have the states in a dictionary. The keys are the state names and the values are arrays of the neighbour state names? If that’s the case, you can do something like this:

typedef State* (^StateBuilder)(NSString *stateName);

NSDictionary *input = …;
NSMutableDictionary *states = [NSMutableDictionary dictionary];

StateBuilder getState = ^(NSString *stateName) {
    State *state = [states objectForKey:stateName];
    if (!state) {
        state = [[State alloc] initWithName:stateName];
        [states setObject:state forKey:stateName];
    }
    return state;
};

for (NSString *stateName in [input allKeys]) {
    State *state = getState(stateName);
    NSMutableSet *neighbours = [NSMutableSet set];
    for (NSString *neighbourName in [input objectForKey:stateName])
        [neighbours addObject:getState(neighbourName)];
    [state setNeighbours:neighbours];
}

The results will end up in [states allValues]. Of course, the block voodoo is not necessary, you can turn the states dictionary into an instance variable and use a regular method instead of the block.

他のヒント

There's no reason that what you describe won't work, although it's going to be long and boring setting this all up in code:

State * california = [State stateWithName:@"California"];
State * oregon = [State stateWithName:@"Oregon"];
State * nevada = [State stateWithName:@"Nevada"];
// And so on, forty-seven more times.
// Stick them in an array or something?
// Now use all those instances that you've just created to set up 
// the neighboring states.
[california setNeighboringStates:[NSSet setWithObjects:oregon, nevada, nil];
[oregon setNeighboringStates:[NSSet setWithObjects:washington, california, idaho, nevada, nil];
// And so on, forty-seven more times.

When you've got data like this, though, that's fixed for the lifetime of the application, you'll want to look into sticking it into some sort of data file and then unarchiving it at runtime.

Create a Country class, which also serves as an State factory.

Thus, States do not create other States, they get them from the Country they belong to.

Similarly, clients do not create States, but request them from the Country.

Requests for States from the Country could also verify a State is properly initialized for public use before returning it -- because you can't 'simply' initialize 48 codependents (neighboringStates).

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top