NSMutableDictionary setObject:forKey (ios 6 without ARC) 结果为 NULL

Posted

技术标签:

【中文标题】NSMutableDictionary setObject:forKey (ios 6 without ARC) 结果为 NULL【英文标题】:NSMutableDictionary setObject:forKey (ios 6 without ARC) results in NULL 【发布时间】:2012-11-26 16:12:16 【问题描述】:

以下代码在升级到 ios 6 之前可以运行。它也可以在 5.1 iPhone 模拟器中运行,但在 6.0 模拟器和设备上会失败。

尝试在 NSMutableDictionary 的循环中设置对象:forKey。已尝试在循环中添加(如下面的代码所示),并尝试使用对象和键的数组进行初始化,这会导致相同的失败。另一个奇怪的信息是,有时它有效,但大部分时间都失败了。添加的对象是 UILocalNotification,键是表示 WeekDay 的对象(不仅仅是一个简单的字符串)。运行的输出如下图所示。 UILocalNotifications 和键显然不是 NULL,但 MutableDictionary 中添加的对在大多数情况下对于某些对象具有 NULL。大多数情况下,它是最后添加的日期(键),其对象为空。我完全不知道这是如何破坏的,在此先感谢您的帮助!

WeekDay 的复制方法(NSCopying 协议):

- (id)copyWithZone:(NSZone *)zone

    WeekDay * copy = [[WeekDay alloc] initWithDay:self.day];
    return copy;

使用 setObject:forKey: 编写 sn-p 代码

NSMutableDictionary * newAlarmsDictionary = [[NSMutableDictionary alloc] init];
NSArray * theDayKeys = [[_daysEnabledDict allKeys] sortedArrayUsingSelector:@selector(compare:)];

NSMutableArray * tempNotifyArray = [[NSMutableArray alloc] init];
UILocalNotification * theAlarm = nil;
WeekDay * theWeekDay = nil;

for (int i=0; i < [theDayKeys count]; i++) 

    if ([[_daysEnabledDict objectForKey:[theDayKeys objectAtIndex:i]] boolValue] == TRUE) 

        theWeekDay = [theDayKeys objectAtIndex:i];

        NSDate * now = [NSDate date];

... deleted lines setting up fire date for UILocalNotification, not significant to problem ...

        theAlarm = [[UILocalNotification alloc] init];
        theAlarm.fireDate = itemDate;
        theAlarm.repeatInterval = NSWeekCalendarUnit;
        theAlarm.timeZone = [NSTimeZone localTimeZone];
        theAlarm.soundName = UILocalNotificationDefaultSoundName;
        theAlarm.applicationIconBadgeNumber = 0;

        [newAlarmsDictionary setObject:theAlarm forKey:theWeekDay];
        [tempNotifyArray addObject:theAlarm];
        [theAlarm release];
        
    

NSLog(@"--Debug: tempNotifyArray---- %@ -------------", tempNotifyArray);
NSLog(@"--Debug: newAlarmsDictionary ====== %@ =============", newAlarmsDictionary);

这里是代码sn-p末尾的两条NSlog语句的输出。这个特殊的运行增加了 4 个通知,从周三到周六。放入 tempNotifyArray 的“警报”是有效的,但在添加到字典时(在本例中为一个)为空。

2012-11-26 11:07:01.087 MedTrack[9728:11303] --Debug: tempNotifyArray---- (

"<UIConcreteLocalNotification: 0x7277940>fire date = Wednesday, November 28, 2012, 11:06:00 AM Eastern Standard Time, time zone = America/Toronto (EST) offset -18000, repeat interval = NSWeekCalendarUnit, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Wednesday, November 28, 2012, 11:06:00 AM Eastern Standard Time, user info = \n    Temp = Fred;\n",


"<UIConcreteLocalNotification: 0x8883280>fire date = Thursday, November 29, 2012, 11:06:00 AM Eastern Standard Time, time zone = America/Toronto (EST) offset -18000, repeat interval = NSWeekCalendarUnit, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Thursday, November 29, 2012, 11:06:00 AM Eastern Standard Time, user info = \n    Temp = Fred;\n",


"<UIConcreteLocalNotification: 0x75c6590>fire date = Friday, November 30, 2012, 11:06:00 AM Eastern Standard Time, time zone = America/Toronto (EST) offset -18000, repeat interval = NSWeekCalendarUnit, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Friday, November 30, 2012, 11:06:00 AM Eastern Standard Time, user info = \n    Temp = Fred;\n",


"<UIConcreteLocalNotification: 0x75c83e0>fire date = Saturday, December 1, 2012, 11:06:00 AM Eastern Standard Time, time zone = America/Toronto (EST) offset -18000, repeat interval = NSWeekCalendarUnit, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Saturday, December 1, 2012, 11:06:00 AM Eastern Standard Time, user info = \n    Temp = Fred;\n"

) -------------

2012-11-26 11:07:01.097 MedTrack[9728:11303] --Debug: newAlarmsDictionary ====== 


"[WeekDay] 6 (Sat)" = (null);


"[WeekDay] 3 (Wed)" = "<UIConcreteLocalNotification: 0x7277940>fire date = Wednesday, November 28, 2012, 11:06:00 AM Eastern Standard Time, time zone = America/Toronto (EST) offset -18000, repeat interval = NSWeekCalendarUnit, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Wednesday, November 28, 2012, 11:06:00 AM Eastern Standard Time, user info = \n    Temp = Fred;\n";


"[WeekDay] 4 (Thu)" = "<UIConcreteLocalNotification: 0x8883280>fire date = Thursday, November 29, 2012, 11:06:00 AM Eastern Standard Time, time zone = America/Toronto (EST) offset -18000, repeat interval = NSWeekCalendarUnit, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Thursday, November 29, 2012, 11:06:00 AM Eastern Standard Time, user info = \n    Temp = Fred;\n";


"[WeekDay] 5 (Fri)" = "<UIConcreteLocalNotification: 0x75c6590>fire date = Friday, November 30, 2012, 11:06:00 AM Eastern Standard Time, time zone = America/Toronto (EST) offset -18000, repeat interval = NSWeekCalendarUnit, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Friday, November 30, 2012, 11:06:00 AM Eastern Standard Time, user info = \n    Temp = Fred;\n";    

【问题讨论】:

你是如何实现WeekDaycopy方法的? 建议不要在没有初始化的情况下创建变量,至少初始化为nil,否则会指向内存垃圾。 UILocalNotification * theAlarm = nil;工作日 * theWeekDay = nil; ARC 是否抱怨 [theAlarm release] 行? @mashdup:Bejan 没有使用 ARC,见标题。 基于@deanWombourne的cmets更新,增加了WeekDay的copy方法(NSCopying协议)。 【参考方案1】:

这里的问题是你实现了-copyWithZone:,但是你没有实现-isEqual:。在不了解对象的完整结构的情况下,我无法回答应该如何实现,但这里有一个很好的基础:

- (BOOL)isEqual:(id)otherObject;

    if ([otherObject isKindOfClass:[self class]]) 
        WeekDay *otherWeekDay= (WeekDay *)otherObject;
        if (self.day != [otherWeekDay day]) return NO;
        if (self.name != [otherWeekDay name]) return NO;
        return YES;
    
    return NO;


- (NSUInteger) hash;

    return self.day ^ [self.name hash];

【讨论】:

你是说如果对象中的变量相同,即使 -hash 不同,我应该覆盖 isEqual 以返回 yes?文档说这是不行的。 不,您还必须实现 -hash,就像在 Java 中一样。 工作。因此,如果我理解正确,由于 NSMutableDictionary 中的优化,我用作包含基本类型和字符串的键的对象在相等性测试中发生冲突?这是我添加到 WeekDay 的代码,我用作键的对象... 哎呀,将代码添加到我用来修复的答案中。我认为“instancetype”仅在使用我未启用的 clang 开关时可用。 @BejanShemirani 别担心,伙计。需要-isEqual: 的原因是因为NSDictionary 复制了它的密钥。如果它没有检查-isEqual:,那么另一个对象不可能具有与您刚刚复制的对象相同的引用。哈希只是另一种测试相等性的方法,主要用于集合存储。

以上是关于NSMutableDictionary setObject:forKey (ios 6 without ARC) 结果为 NULL的主要内容,如果未能解决你的问题,请参考以下文章

两个NSMutableDictionary合并成一个NSMutableDictionary

如何将 NSArray 添加为 NSMutableDictionary 的 NSMutableDictionary 键?

如何获得 NSDictionary/NSMutableDictionary 的原始顺序?

类别 NSMutableDictionary/NSDictionary 应该返回 NSMutableDictionary/NSDictionary 取决于调用者类

如何更新 NSMutableDictionary?

NSMutableDictionary 奇怪的问题