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(服务器)端弄清楚,那么这里的 NSDictionaryNSArray 类别会删除任何 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

将占位符文本添加到文本字段时,iOS 7 中的应用程序崩溃

为啥我的弹出框在 iPhone 6 Plus 上的 iOS 8.1 中崩溃? iOS 8 工作(实际上是 Xcode 6.0 到 6.1 的错误)

React-Native-Camera 不能在 IOS 上工作但在 Android 上工作,IOS 应用程序崩溃