NSUserDefaults setObject 方法导致应用在 ios8 中崩溃

Posted

技术标签:

【中文标题】NSUserDefaults setObject 方法导致应用在 ios8 中崩溃【英文标题】:NSUserDefaults setObject method causes the app to crash in ios8 【发布时间】:2014-10-09 07:42:32 【问题描述】:

我有一个应用程序,我在其中使用 NSUserDefaults 在 vi​​ewControllers 之间传递一些数据。

这是我正在使用的下面的代码。

[[NSUserDefaults standardUserDefaults]setObject:selectedLists forKey:UserID];

其中 selectedListsNSMutableArray,而 UserID 是 NSString

此代码在 ios7 和 xCode5 之前都可以正常工作。

由于我更新了 xCode6,现在我正在使用 ios8,我的应用程序在 xCode 6 和 ios 7.1 上运行良好,但是当我在 ios8 设备上运行应用程序时应用程序崩溃并出现以下错误。

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber length]: unrecognized selector sent to instance 0x7a027060'

我只是不明白这里有什么问题。

如果有人在使用 ios8 时遇到过这个问题,请帮助我。

提前致谢。

selectedLists的值

    
        CardFace = Word;
        ImportFlag = Import;
        ListID = 1;
        ListName = "Adjectives - Appearance";
        QuizBy = Definition;
        UserID = 1;
    

UserId 为 1。

已编辑

 *** First throw call stack:
    (
        0   CoreFoundation                      0x06a24df6 __exceptionPreprocess + 182
        1   libobjc.A.dylib                     0x03ac8a97 objc_exception_throw + 44
        2   CoreFoundation                      0x06a2ca75 -[NSObject(NSObject) doesNotRecognizeSelector:] + 277
        3   CoreFoundation                      0x069759c7 ___forwarding___ + 1047
        4   CoreFoundation                      0x0697558e _CF_forwarding_prep_0 + 14
        5   CoreFoundation                      0x068df30f CFStringGetLength + 143
        6   CoreFoundation                      0x069de510 _CFPrefsEncodeKeyValuePairIntoMessage + 64
        7   CoreFoundation                      0x06a275cf -[CFPrefsPlistSource sendMessageSettingValue:forKey:] + 111
        8   CoreFoundation                      0x06954f3a -[CFPrefsPlistSource alreadylocked_setValue:forKey:] + 250
        9   CoreFoundation                      0x06954e22 -[CFPrefsSource setValue:forKey:] + 82
        10  CoreFoundation                      0x06954dc3 ___CFPreferencesSetValueWithContainer_block_invoke + 51
        11  CoreFoundation                      0x0690ef0a +[CFPrefsSource withSourceForIdentifier:user:byHost:container:perform:] + 1274
        12  CoreFoundation                      0x06954d61 _CFPreferencesSetValueWithContainer + 225
        13  CoreFoundation                      0x06a0aa62 _CFPreferencesSetAppValueWithContainer + 66
        14  Foundation                          0x0347f53f -[NSUserDefaults(NSUserDefaults) setObject:forKey:] + 59
        15  Foundation                          0x0353eeba -[NSUserDefaults(NSKeyValueCoding) setValue:forKey:] + 68
        16  Vocab                               0x000eaecc Vocab + 720588
        17  libobjc.A.dylib                     0x03ade7cd -[NSObject performSelector:withObject:withObject:] + 84
        18  UIKit                               0x022a079d -[UIApplication sendAction:to:from:forEvent:] + 99
        19  UIKit                               0x022a072f -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 64
        20  UIKit                               0x023d3a16 -[UIControl sendAction:to:forEvent:] + 69
        21  UIKit                               0x023d3e33 -[UIControl _sendActionsForEvents:withEvent:] + 598
        22  UIKit                               0x023d309d -[UIControl touchesEnded:withEvent:] + 660
        23  UIKit                               0x022f0aba -[UIWindow _sendTouchesForEvent:] + 874
        24  UIKit                               0x022f1595 -[UIWindow sendEvent:] + 791
        25  UIKit                               0x022b6aa9 -[UIApplication sendEvent:] + 242
        26  UIKit                               0x022c68de _UIApplicationHandleEventFromQueueEvent + 20690
        27  UIKit                               0x0229b079 _UIApplicationHandleEventQueue + 2206
        28  CoreFoundation                      0x069487bf __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
        29  CoreFoundation                      0x0693e2cd __CFRunLoopDoSources0 + 253
        30  CoreFoundation                      0x0693d828 __CFRunLoopRun + 952
        31  CoreFoundation                      0x0693d1ab CFRunLoopRunSpecific + 443
        32  CoreFoundation                      0x0693cfdb CFRunLoopRunInMode + 123
        33  GraphicsServices                    0x0436424f GSEventRunModal + 192
        34  GraphicsServices                    0x0436408c GSEventRun + 104
        35  UIKit                               0x0229ee16 UIApplicationMain + 1526
        36  Vocab                               0x0004c9bc Vocab + 72124
        37  libdyld.dylib                       0x03ee6ac9 start + 1
    )
    libc++abi.dylib: terminating with uncaught exception of type NSException

已编辑 在我的 tableview 的 didselect 方法上...

UserID = [[users objectAtIndex:indexPath.row] valueForKey:@"UserID"];

其中 users 是一个数组。

【问题讨论】:

selectedLists和UserID是什么类型的对象? 我建议你设置一个异常断点或检查堆栈跟踪以确认它实际上是在哪一行崩溃 另外,NSUserDefaults 可能不是在对象之间传递数据的最有效方式 - NSNotificationCenter 是更好的选择 我已经编辑了我的问题。 【参考方案1】:

您应该检查 UserID 类型,因为崩溃与将 NSArray 更改为 NSMutableArray 无关。

您一定是在您的用户 ID 上将 NSNumber 与 NSString 混淆了:

更改您的代码,使用变量 userIDString 代替 userID

NSString userIDString;

//If UserID is class of NSNumber turn its value to NSString
if ([UserID isKindOfClass:[NSNumber class]]) 
 
    userIDString = [UserID stringValue]; 
 
else 
    userIDString = UserID ;

【讨论】:

@Manthan 您不能将自定义对象的 NSMutableArray 存储到 userDefaults。您需要将其表示为 NSData。生病编辑我的答案。 好的,谢谢...但它适用于 ios6 和 ios7 那为什么这个问题只出现在 ios8 上? 我不知道您是如何真正将这些自定义对象传递给 NSUserDefaults,但这是一个众所周知的问题,即您无法将对象传递给 NSUserDefaults。如果你的数组上有 NSDictionaries,那么逻辑就会改变。 实际上我有一个现有的项目,我正在做一些修改,所以我不知道其他开发人员所做的一些更改。很抱歉。 当我写这个时 [[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:selectedLists] forKey:UserID];应用仍然崩溃。【参考方案2】:

在运行时UserId 可能是NSNumber 类型,即使在您的代码中它是NSString 类型。

检查UserId 是如何创建的。使用调试器检查运行时类型。

新发布的代码显示您从可能包含字典的users 数组中检索UserId。在这些字典中,键 UserID 有一个值。这取决于字典数组是如何创建的(json 反序列化?),但UserID 键引用的对象类型似乎是数字类型,而不是字符串。所以你所要做的就是把这个数字转换成一个字符串:

UserID = [[[users objectAtIndex:indexPath.row] valueForKey:@"UserID"] stringValue];

现在您的密钥始终是一个字符串。

【讨论】:

yes user id 是 1 所以它是 nsnumber 但它是 nsstring @Manthan 密钥不能是NSNumber,它必须是NSString。再次检查密钥是如何创建的,并在必要时将其转换为字符串。 好的,我会尽力告诉你的。 我已将用户 ID 设为 nsstring 但它返回 nsnumber 那我该怎么办? 该错误出现在您尚未发布的代码中。正如我所说,检查创建UserId 对象的代码。你从哪里得到它?将此信息/代码添加到您的问题中,否则我们将无法发布解决方案。【参考方案3】:

尝试在NSData 中编码您的数据并将其保存在NSUserDefaults 中,并在需要时取回。看看this 线程和this 一个。

【讨论】:

@Downvoter,请注意解释投反对票的原因,我不会给你类似的无声投反对票 :)【参考方案4】:

不应使用 NSUSerdefault 来保留自定义对象的集合。 您应该使用 NSkeyedUnarchiver/NSkeyedarchiver 保存它们。 参考:NSCoding。

【讨论】:

【参考方案5】:

我认为自 iOS8 以来无法将 NSMutableArrays 存储在 NSUserDefaults 中(根据不同的帖子)。尝试将其转换为之前的数组(或创建一个新数组)。

例如这样:

NSArray *arr = [NSArray arrayWithArray:selectedLists];

并将arr 存储在NSUserDefaults 中。

【讨论】:

你可以将 NSMutableArray 存储到 NSUserDefaults 但是当你得到它时,这个数组不是一个可变对象,所以你必须创建一个新的。 我在应用程序中遇到了完全相同的崩溃,使用 NSArray 解决了我的问题 ***.com/questions/26029704/… 显然这是 iOS8 的新功能,也许吧? IOS 8 发布时出现同样的问题 (NSMutable > NSUserDefaults) 并用非可变数组替换 mymutable 解决了我的问题... 我刚刚运行了一个测试,在其中我将 NSMutableArray 添加到 NSUserDefaults 并将其作为数组检索 - 没问题

以上是关于NSUserDefaults setObject 方法导致应用在 ios8 中崩溃的主要内容,如果未能解决你的问题,请参考以下文章

NSUserDefaults setObject:forKey 死锁?

NSUserDefaults setObject 方法导致应用在 ios8 中崩溃

NSUserDefaults存取失败

NSUserDefaults的使用

同步 NSUserDefaults 没有效果

使用常量 NSString 作为 NSUserDefaults 的键