0

我已经很久没有实现二进制了,最近有一个要求(为了演示一些代码),我开始使用:

@interface NSNode : NSObject

@property (strong, nonatomic) NSNode *leftChild;
@property (strong, nonatomic) NSNode *rightChild;

但后来,似乎每当我需要对两个节点做某事时,我都需要写两次——一次给左孩子,一次给右孩子,除非我把需要做的事情变成一个额外的方法, 并仔细传递正确的参数——为了实现这一点,会有很多额外的方法。

如果它是通过使用 NSMutableArray 完成的

typedef enum {
    NSNodeLeft = 0,
    NSNodeRight
} NSNodeLeftOrRightSide;

@interface NSNode : NSObject

@property (strong, nonatomic) NSMutableArray *children;

然后我总是可以使用循环对两个节点做一些事情:

for (NSNode *node in self.children) {
    // do something
}

或者如果需要一个索引来判断它是左孩子还是右孩子:

[self.children enumerateObjectsUsingBlock:
    ^(NSNode *node, NSUInteger nodeIndex, BOOL *stop) {
        // do something
    }
];

并且nodeIndex可以用来确定它是左孩子还是右孩子。

更重要的是,这个类可以很容易地扩展到具有 N 个孩子的树。这实际上是一个更好的做法吗?除了使用数组的性能非常小之外,还有什么缺点吗?(我之所以选择NSMutableArray不是,是NSArray因为如果我们需要制作这个 N-children,我们不需要将其更改为NSMutableArray所有地方)。

4

2 回答 2

3

当您需要对两个孩子做某事时,您总是可以使用数组

for (Node *node in @[self.leftChild, self.rightChild]) {
    // ...
}

如果你想让它更简单,你可以定义一个- (NSArray *)children返回的方法@[self.leftChild, self.rightChild]。但是将可变属性保留为不同的子节点很有用,因为它明确编码了您的节点只有 2 个子节点而不是无限数量的子节点这一事实。

于 2012-09-08T05:58:28.537 回答
2

首先,您不应该使用名称NSNode。Apple 保留NS前缀供自己使用。

其次,只给你的Node班级自己的枚举信息。

@interface Node : NSObject

- (void)enumerateChildrenUsingBlock:(void (^)(Node *child, NSUInteger childIndex, BOOL *stop))block;

// I prefer this shorter name style in my own classes:
- (void)forEachChild:(void (^)(Node *child, NSUInteger childIndex, BOOL *stop))block;

实现它很简单:

@implementation Node

- (void)enumerateChildrenUsingBlock:(void (^)(Node *child, NSUInteger childIndex, BOOL *stop))block {
    BOOL stop = NO;
    block(self.leftChild, 0, &stop);
    if (!stop) {
        block(self.rightChild, 1, &stop);
    }
}

如果你实现了NSFastEnumeration协议,你也可以像这样编写一个 for/in 循环:

for (Node *child in parentNode) {
    // do something with child
}

你可以NSFastEnumeration这样实现:

@interface Node : NSObject <NSFastEnumeration>
...

@implementation Node

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)stackbufCount {
    // The compiler initializes state->state to 0 at the start of the for...in loop.
    // I use it to track which children have been returned.
    // 0 = no children returned yet
    // 1 = left children returned
    // 2 = both children returned

    state->itemsPtr = stackbuf;
    state->mutationsPtr = (__bridge unsigned long *)self;

    NSUInteger count = 0; // number of children I'm returning on this call
    if (state->state < 1 && count < stackbufCount) {
        stackbuf[count++] = self.leftChild;
        ++state->state;
    }
    if (state->state < 2 && count < stackbufCount) {
        stackbuf[count++] = self.rightChild;
        ++state->state;
    }

    return count;
}

看看这篇文章了解更多关于快速枚举的信息:http: //www.mikeash.com/pyblog/friday-qa-2010-04-16-implementing-fast-enumeration.html

于 2012-09-08T05:58:19.543 回答