为什么我在Objective C中有一个深层副本的麻烦? [英] Why am I having trouble with a deep copy in Objective C?

查看:123
本文介绍了为什么我在Objective C中有一个深层副本的麻烦?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我假设我如何执行深度复制的理解不只是在那里。同样的一些次优的内存处理,我在下面执行。下面的代码可能描述了一个浅拷贝,我相信这是我的问题可能在哪里。我有一些cookie切割器代码的示例,如下所示:

I'm assuming my understanding of how to perform a deep copy isn't just there yet. The same with some sub-optimal memory handling that I'm performing down below. This code below probably depicts a shallow copy, and I believe that's where my problem might be. I have some cookie-cutter code for an example that looks like the following:

NSArray *user = [[xmlParser createArrayWithDictionaries:dataAsXML
                                              withXPath:kUserXPath] retain];
if([user count] > 0) {
    self.name = [[user valueForKey:@"name"] copy];
}

// Crash happens if I leave the next line un-commented.
// But then we have a memory leak.
[user release]; 

[xmlParser release];

不幸的是,当我注释 [用户发布] ,代码工作,但我们有一个明显的内存泄漏。昨天当S​​O社区帮助我理解更好的内存管理时,方法 createArrayWithDictionaries:withXPath:被重构。这是它的样子:

Unfortunately when I comment out [user release], the code works, but we have an obvious memory leak. The method createArrayWithDictionaries:withXPath: was refactored last night when the SO community helped me understand better memory management. Here's what it looks like:

- (NSArray *)createArrayWithDictionaries:(NSString *)xmlDocument 
                               withXPath:(NSString *)XPathStr {
    NSError *theError = nil;
    NSMutableArray *dictionaries = [NSMutableArray array];
    CXMLDocument *theXMLDocument = [CXMLDocument alloc];
    theXMLDocument = [theXMLDocument initWithXMLString:xmlDocument
                                               options:0
                                                 error:&theError]; 
    NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError];

    for (CXMLElement *xmlElement in nodes) {
        NSArray *attributes = [xmlElement attributes];
        NSMutableDictionary *attributeDictionary;
        attributeDictionary = [NSMutableDictionary dictionary];
        for (CXMLNode *attribute in attributes) {
            [attributeDictionary setObject:[attribute stringValue]
                                    forKey:[attribute name]];
        }

        [dictionaries addObject:attributeDictionary];
    }

    [theXMLDocument release];
    return dictionaries;
} 

我猜这里可能有几个问题:

I'm guessing there's a couple of issues that might be going on here:


  • 自动发布我的字典数组,因此我的应用程式崩溃。

  • 我不是执行深拷贝,只是浅拷贝。因此,当用户数组被释放时, self.name 即可完成。

  • Auto release on my dictionaries array is happening, thus my app crashing.
  • I'm not performing a deep copy, only a shallow copy. Thus when the user array is released, self.name is done for.

NSZombieEnabled ,我看到以下内容:


*** -[CFString respondsToSelector:]:
     message sent to deallocated instance 0x1ae9a0

此外,回溯跟踪显示这是崩溃的最终调用包含以下代码与另外两个方法分开:

Also, the final call where the backtrace shows this is crashing contains the following code in a separate module from the other two methods:

User *u = self.user;
NSString *uri = [NSString stringWithFormat:@"%@/user/%@/%@",
                         [self groupName], u.userId, kLocationsUri];

在客户端代码和之间发生的所有自动发布/ createArrayWithDictionaries:withXPath ,我有点困惑,这里的真正的问题。

Between all the auto releasing/copies/retain happening between the client code and createArrayWithDictionaries:withXPath, I'm a bit confused as to the real problem here. Thanks again for helping me understand.

推荐答案


我的字典数组上的自动发布正在发生,因此我的应用崩溃。

Auto release on my dictionaries array is happening, thus my app crashing.

如果调用者打算将数组保存在某处,它需要保留它。

If the caller intends to keep the array around somewhere, it needs to retain it. Otherwise, it will crash when it tries to access the (now-deceased) object.

如果调用者要将它存储在一个属性中,它必须使用 self.dictionaries = [...] 语法,不是 dictionaries = [...] 。前者是一个属性访问,它调用setter方法;后者是一个直接的实例变量赋值。

If the caller is going to store it in a property, it must use the self.dictionaries = […] syntax, not dictionaries = […]. The former is a property access, which calls the setter method; the latter is a direct instance variable assignment.

回到你的实际问题,一个深层副本:你需要获取每个元素的子元素

Coming back to your actual question, that of a deep copy: You need to get the sub-elements of every element and put them in each element's dictionary.

基本上,你需要一个递归方法(或者一个队列,但这是更难的文件过早优化,直到你证明你需要它)它接受一个元素并返回一个字典,然后你需要在每个元素的子元素上调用此方法,并将结果收集到一个数组中,并将其放入您正在创建的字典。

Basically, you need a recursive method (or a queue, but that's harder—file under premature optimization until you've proven you need it) that takes an element and returns a dictionary, and then you need to call this method on each of your element's child elements, and collect the results into an array and put that into the dictionary you're creating.

我建议使用递归方法作为元素的实例方法。类似:

I would recommend making this recursive method an instance method of the element. Something like:

- (NSDictionary *) dictionaryRepresentation {
    NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary];
    for (CXMLNode *attribute in attributes) {
        [attributeDictionary setObject:[attribute stringValue] forKey:[attribute name]];
    }

    NSArray *childElements = [self childElements];

    return [NSDictionary dictionaryWithObjectsAndKeys:
        attributeDictionary, @"attributes",
        [childElements valueForKey:@"dictionaryRepresentation"], @"childElements",
        nil];
}

然后你替换 createArrayWithDictionaries中的循环:withXPath: 与类似的 valueForKey:消息。我会离开你填写它。

Then you replace the loop in createArrayWithDictionaries:withXPath: with a similar valueForKey: message. I'll leave you to fill it in.

valueForKey:是Key-Value Coding的主要方法。在这两个地方,我们使用 NSArray的方便实现它

valueForKey: is Key-Value Coding's principal method. In both places, we're making use of NSArray's handy implementation of it.

(如果使用 valueForKey :仍然没有意义,您应该阅读 KVC编程指南。KVC在现代Cocoa中非常重要,因此您需要迟早阅读。)

(If the use of valueForKey: still doesn't make sense to you, you should read the KVC Programming Guide. KVC is vitally important in modern Cocoa, so you do need to read this sooner or later.)

这篇关于为什么我在Objective C中有一个深层副本的麻烦?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆