iphone - 保留本地创建的 NSMutableDictionary——是否必要?

标签 iphone objective-c cocoa-touch ios

大家好,我对这里的一段代码有一些疑问,非常感谢您的反馈。基本上我正在创建一个临时的 NSMutableDictionary 以便从 plist 中提取一些值。然后,我将检查其中一个值,以确定是否要对 plist 执行任何其他操作。

代码如下,但我的问题如下:

1)主要问题

因为我可能会将这个本地创建的字典传递给另一个方法,以便在那里用作源数据,所以我需要在此处保留字典吗?如果是这样,正确的方法是什么?

我还在学习这门语言,除了不知道这里是否需要保留/释放之外,我在下面实现的方法似乎没有做任何事情。当我在发布前后将字典转储到控制台时,会打印出相同的值(尽管即使发布成功也可能会发生这种情况,因为还没有其他东西覆盖该内存段吗?)

2) 不太重要的问题:

“return”是否立即跳出整个“multitaskingResumeCheck”函数,而不执行任何进一步的内部代码?或者它只是跳出“else”循环?我尝试将“NSMutableDictionary *dict”字典创建放入 filemanager if 循环中,但我从“NSNumber *wrappedATZ...”行中收到有关未声明字典的错误。我在这里犯了什么错误?

在此先感谢您的所有帮助。我在所有相关行上都放置了“//QUESTION TAG”。

- (void) multitaskingResumeCheck {

NSLog(@"Running multitaskingResumeCheck");

// Get the path to the "Documents" directory

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

// Get the path to our plist ("Documents/foo.plist")

NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:@"lastStopwatchState.plist"];

// check if our plist already exists in the Documents directory

NSMutableDictionary *dict; // QUESTION TAG (Why can't I do this in the "filemanager if" below)

NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:plistPath]) {
    // If it does, read it.     
    NSLog(@"dict existed, reading %@", plistPath);
    dict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];

    [dict retain]; // QUESTION TAG (Necessary? If so, correct?)

} else {
    // If not, we're done here.
    return;
}

// Now check whether the timers were zeroed on exit

NSNumber *wrappedATZ = [dict valueForKey:@"allTimersZeroed"]; // QUESTION TAG (Got undeclared error if dict declaration was in wrong place (see above). Maybe I misunderstand "return"?
BOOL timersWereZeroed = [wrappedATZ boolValue];

// If they were not Zeroed, then we'll load in our data

if (!timersWereZeroed) {
    NSLog(@"Timers were not zeroed. Loading Data.");
    [self loadResumeData:dict];
}

// Dump the contents of the dictionary to the console
NSLog(@"dumping...");
for (id key in dict) {
    NSLog(@"key=%@, value=%@", key, [dict objectForKey:key]);
}   

[dict release]; // QUESTION TAG (Necessary? If so, correct?)

// Dump the contents of the dictionary to the console
NSLog(@"dumping...");
for (id key in dict) {
    NSLog(@"key=%@, value=%@", key, [dict objectForKey:key]);
}   

最佳答案

您的问题在Cocoa Memory Management Rules 中或多或少得到了完整的回答。尽管可能并不完全清楚究竟是如何做到的。

首先,您应该重构您的代码,使大括号结构与实际的控制流相匹配。即,

之后的所有内容
else
{
    return;
}

应该在 if 部分内,所以它看起来像这样:

- (void) multitaskingResumeCheck {

    // Some stuff not relevant to the question

    NSFileManager *fileManager = [NSFileManager defaultManager];
    if ([fileManager fileExistsAtPath:plistPath]) {
        // If it does, read it.     
        NSLog(@"dict existed, reading %@", plistPath);
        NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];

        [dict retain]; // QUESTION TAG (Necessary? If so, correct?)

        // Some stuff not relevant to the question

        if (!timersWereZeroed) {
            NSLog(@"Timers were not zeroed. Loading Data.");
            [self loadResumeData:dict];
        }

        // Dump the contents of the dictionary to the console
        NSLog(@"dumping...");
        for (id key in dict) {
            NSLog(@"key=%@, value=%@", key, [dict objectForKey:key]);
        }

        [dict release]; // QUESTION TAG (Necessary? If so, correct?)
    }

我已将 else 部分之后的所有内容移至 if 部分,因为它实际上完全相同。由于 dict 现在不再使用,除了 if 部分,我将它的声明移到了那里。我还删除了第二个转储,因为 dict 不再存在于同一范围内。除此之外,这在功能上与您拥有的相同。

内存管理规则的要点之一是:

A received object is normally guaranteed to remain valid within the method it was received in, and that method may also safely return the object to its invoker.

这回答了您的第一个问题。您从 +dictionaryWithContentsOfFile: 收到的字典将在该方法中保持有效。这包括此方法调用的任何方法,将 dict 作为参数传递。因此,在这种情况下,不需要保留和释放。之前第二个转储起作用的原因是保留和释放对对字典的所有权没有实际影响。

在回答您的第二个问题时,return 会立即退出该函数,而不会在其后执行任何代码。这就是为什么我能够按照我所做的方式重构功能。

移动 dict 声明时出现错误的原因是,在您的代码中,dict 在 block 外被引用({ ... } 中包含的语句被称为一个 block )在其中声明它。 C 范围规则阻止了这种情况。

最后,要记录字典的内容,您可以这样做:

 NSLog(@"%@", dictionary);

无需循环键。

关于iphone - 保留本地创建的 NSMutableDictionary——是否必要?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5534465/

相关文章:

iPhone - 用户默认值和 UIImages

ios - App Transfer 后用户会收到 Apple Push Notification Message 吗?

iphone - 在具有分发配置文件的设备上运行时应用程序崩溃

ios - 在 MPMoviePlayer 中获取视频的总播放时长

iphone - 键盘附件 View 隐藏文本

ios - 如何与 UISearchController 演示/解雇动画一起制作动画?

ios - CUI目录 : Invalid asset name supplied warning

ios - 为什么我不能停止 NSTimer?

ios - 如何在 swift3 中播放 mp3 文件?

iphone - 滑动以删除 UITableView 问题中的选项