iOS 8 工作但 iOS 7 崩溃 -[NSNull 长度]: unrecognized selector sent to instance
Posted
技术标签:
【中文标题】iOS 8 工作但 iOS 7 崩溃 -[NSNull 长度]: unrecognized selector sent to instance【英文标题】:iOS 8 works but iOS 7 crashes with -[NSNull length]: unrecognized selector sent to instance 【发布时间】:2014-12-09 07:56:01 【问题描述】:我一直在寻找这个问题的答案,但仍然无法解决如何解决这个问题。这个-[NSNull length]: unrecognized selector sent to instance 和这个[NSNull length]: unrecognized selector sent to instance 0x43fe068 没有帮助。
我正在开发一个带有 Parse 后端的聊天应用程序,但我遇到了一个时间戳问题,聊天消息出现乱序,因此我使用 Databrowser 从我的 Parse 数据库中删除了乱序的行.当我测试应用程序时,这似乎解决了我的 iPhone 6 Plus 和运行 ios 8 的 iPhone 6 模拟器上的问题。但是,当我在运行 iOS 7 的 iPhone 5s 上打开同一个聊天室时,应用程序始终崩溃以下错误。
-[NSNull length]: unrecognized selector sent to instance
我不知道为什么删除一行会导致这种情况发生,为什么只在 iOS 7 上发生?我设置了一个 All Exceptions Breakpoint,这里是违规行以及屏幕截图。
self.lastMessageLabel.textColor = [UIColor redColor];
即使我注释掉上面的行,我仍然会收到 NSNull length
崩溃,但它在通用 main.m 处中断。
任何有关如何解决此问题的建议将不胜感激。谢谢。
编辑 1:这是来自我的 ChatView.m 的代码,它正在由我的 PrivateInbox 加载。
- (void)loadMessages
if (isLoading == NO)
isLoading = YES;
JSQMessage *message_last = [messages lastObject];
PFQuery *query = [PFQuery queryWithClassName:PF_CHAT_CLASS_NAME];
[query whereKey:PF_CHAT_ROOM equalTo:chatroomId];
if (message_last != nil)
[query whereKey:PF_CHAT_SENTDATE greaterThan:[self.dateFormatter stringFromDate:message_last.date]];
[query includeKey:PF_CHAT_USER];
[query orderByAscending:PF_CHAT_SENTDATE];
[query addAscendingOrder:PF_CHAT_CREATEDAT];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
if (error == nil)
for (PFObject *object in objects)
PFUser *user = object[PF_CHAT_USER];
[users addObject:user];
if(![object[PF_CHAT_TEXT] isKindOfClass:[NSNull class]])
NSDate* sentDate;
if(object[PF_CHAT_SENTDATE] != nil)
sentDate = [self.dateFormatter dateFromString:object[PF_CHAT_SENTDATE]];
else
sentDate = object.createdAt;
JSQTextMessage *message = [[JSQTextMessage alloc] initWithSenderId:user.objectId senderDisplayName:user.objectId date:sentDate text:object[PF_CHAT_TEXT]];
[messages addObject:message];
else if(object[PF_CHAT_PHOTO] != nil)
NSDate* sentDate;
if(object[PF_CHAT_SENTDATE] != nil)
sentDate = [self.dateFormatter dateFromString:object[PF_CHAT_SENTDATE]];
else
sentDate = object.createdAt;
PFFile* photoFile = object[PF_CHAT_PHOTO];
JSQPhotoMediaItem *photoItem = [[JSQPhotoMediaItem alloc] init];
JSQMediaMessage *photoMessage = [[JSQMediaMessage alloc] initWithSenderId:user.objectId
senderDisplayName:user.objectId
date:sentDate
media:photoItem];
[messages addObject:photoMessage];
[photoFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error)
photoItem.image = [UIImage imageWithData:data];
[self.collectionView reloadItemsAtIndexPaths:[NSArray arrayWithObjects:[NSIndexPath indexPathForItem:[messages indexOfObject:photoMessage] inSection:0], nil]];
];
else if(object[PF_CHAT_VIDEO] != nil)
NSDate* sentDate;
if(object[PF_CHAT_SENTDATE] != nil)
sentDate = [self.dateFormatter dateFromString:object[PF_CHAT_SENTDATE]];
else
sentDate = object.createdAt;
PFFile* videoFile = object[PF_CHAT_VIDEO];
JSQVideoMediaitem *videoItem = [[JSQVideoMediaitem alloc] initWithFileURL:[NSURL URLWithString:[videoFile url]] isReadyToPlay:YES];
JSQMediaMessage *videoMessage = [[JSQMediaMessage alloc] initWithSenderId:user.objectId
senderDisplayName:user.objectId
date:sentDate
media:videoItem];
[messages addObject:videoMessage];
if ([objects count] != 0)
[JSQSystemSoundPlayer jsq_playMessageReceivedSound];
[self resetUnreadCount];
[self finishReceivingMessage];
else [ProgressHUD showError:@"Network error."];
isLoading = NO;
];
编辑 2: 我尝试了 Nick Lockwood https://github.com/nicklockwood/NullSafe 的 NSNullSafe,它允许私人收件箱在不崩溃的情况下打开,并且让我克服了 NSNull 长度错误,但我认为这只是掩盖了问题,我仍然不知道为什么它在 iOS 8 上没有崩溃,但在 iOS 7 上却崩溃了。
【问题讨论】:
【参考方案1】:我认为这与两个操作系统之间的差异无关。
崩溃很明显,您正在向无法处理它的NSNUll
类的对象发送消息。
您通常使用解析或 Web 服务的事实使我认为该对象是由后端生成为 JSON 中的 null
并通过 JSON 解析转换为 NSNull
对象。
您应该找到一种可能在解析级别处理 NSNull 对象的方法。
【讨论】:
我刚刚用额外的代码更新了我的帖子,这样你就可以看到被调用的代码的 NSNull 部分。【参考方案2】:@Andrea 是正确的,如果您无法从您的 API(服务器)端弄清楚,那么这里的 NSDictionary
和 NSArray
类别会删除任何 NSNull
对象并且您的应用程序不会崩溃。
@interface NSDictionary (NullReplacement)
- (NSDictionary *)dictionaryByReplacingNullsWithBlanks;
@end
@interface NSArray (NullReplacement)
- (NSArray *)arrayByReplacingNullsWithBlanks;
@end
@implementation NSDictionary (NullReplacement)
- (NSDictionary *)dictionaryByReplacingNullsWithBlanks
const NSMutableDictionary *replaced = [self mutableCopy];
const id nul = [NSNull null];
const NSString *blank = @"";
for (NSString *key in self)
id object = [self objectForKey:key];
if (object == nul) [replaced setObject:blank forKey:key];
else if ([object isKindOfClass:[NSDictionary class]]) [replaced setObject:[object dictionaryByReplacingNullsWithBlanks] forKey:key];
else if ([object isKindOfClass:[NSArray class]]) [replaced setObject:[object arrayByReplacingNullsWithBlanks] forKey:key];
return [NSMutableDictionary dictionaryWithDictionary:[replaced copy]];
@end
@implementation NSArray (NullReplacement)
- (NSArray *)arrayByReplacingNullsWithBlanks
NSMutableArray *replaced = [self mutableCopy];
const id nul = [NSNull null];
const NSString *blank = @"";
for (int idx = 0; idx < [replaced count]; idx++)
id object = [replaced objectAtIndex:idx];
if (object == nul) [replaced replaceObjectAtIndex:idx withObject:blank];
else if ([object isKindOfClass:[NSDictionary class]]) [replaced replaceObjectAtIndex:idx withObject:[object dictionaryByReplacingNullsWithBlanks]];
else if ([object isKindOfClass:[NSArray class]]) [replaced replaceObjectAtIndex:idx withObject:[object arrayByReplacingNullsWithBlanks]];
return [replaced copy];
@end
注意:仅适用于解析少量数据的情况。
来源:https://***.com/a/16702060/1603234
【讨论】:
【参考方案3】:其他两个答案是正确的 - 这不是操作系统版本的问题,而是您被传递了一个 NULL 值并且没有捕获它。
您在异常中捕获的行:
self.lastMessageLabel.textColor = [UIColor redColor];
表示症状,而不是原因。我不是 100% 确定 _setTextColor 实际是如何工作的,但我敢打赌它是通过使用 NSString/NSAttributedString 的长度属性来制作 NSRange 来工作的,这样它就知道从哪里开始应用颜色并结束应用颜色。如果数据为 NULL,那么正如其他用户所提到的,您正在尝试访问错误类的长度属性,从而导致您的崩溃。
从您的堆栈跟踪来看,第 5 行 (setMessage:forUser) 和 6 (cellForRow...) 是您应该尝试捕获 NULL 值的地方。要么这样,要么您应该修改您的数据控制器,以便在 JSON 中传回 NULL 值时,将其替换为占位符,例如“无消息”。
无论哪种情况,当您在 cellForRow... 中构建 tableView 单元格时为 self.lastMessageLabel.text 分配值时,可能会发生崩溃。检查您在那里使用的 NSString 的类类型(isKindOfClass[NSNULL class]),看看是否有帮助。
【讨论】:
以上是关于iOS 8 工作但 iOS 7 崩溃 -[NSNull 长度]: unrecognized selector sent to instance的主要内容,如果未能解决你的问题,请参考以下文章
NSLayoutConstraints 在 ios 7 上崩溃,但在 ios 8 上没有
需要帮助:“错误的架构”导致应用在 iOS 7 中启动时崩溃,但在 iOS 8 中运行良好
在到达我的代码之前,应用程序在运行时崩溃 xcode6.1 Universal App Objective-C NSKeyedUnarchiver iOS 7.0 iOS 8.1
为啥我的弹出框在 iPhone 6 Plus 上的 iOS 8.1 中崩溃? iOS 8 工作(实际上是 Xcode 6.0 到 6.1 的错误)