0

我一直在寻找这个问题的答案,但仍然无法解决如何解决这个问题。This -[NSNull length]: unrecognized selector sent to instance and this [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:这是我的 PrivateInbox 正在加载的 ChatView.m 中的代码。

- (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 Length 错误,但我认为这只是掩盖了问题,我仍然没有不知道为什么它在 iOS 8 上没有崩溃,但在 iOS 7 上却崩溃了。

4

3 回答 3

1

我不认为这可能与两个操作系统之间的差异有关。
崩溃很清楚,您正在向NSNUll无法处理它的类对象发送消息。
您通常使用解析或 Web 服务的事实使我认为该对象是由后端生成的 JSON 格式的,并通过 JSON 解析null转换为对象。 您应该找到一种可能在解析级别处理 NSNull 对象的方法。NSNull

于 2014-12-09T08:15:56.540 回答
0

其他两个答案是正确的 - 这不是操作系统版本的问题,而是您被传递了一个 NULL 值并且没有捕获它。

您在异常中捕获的行:

 self.lastMessageLabel.textColor = [UIColor redColor];

表示症状,而不是原因。我不是 100% 确定 _setTextColor 实际是如何工作的,但我敢打赌它通过使用 NSString/NSAttributedString 的长度属性来制作 NSRange 以便它知道从哪里开始应用颜色并结束应用颜色。如果数据为 NULL,那么正如其他用户所提到的,您正在尝试访问错误类的长度属性,从而导致崩溃。

从您的堆栈跟踪来看,第 5 行 (setMessage:forUser) 和 6 (cellForRow...) 是您应该尝试捕获 NULL 值的地方。要么,要么您应该修改您的数据控制器,以便在 JSON 中传回 NULL 值时,将其替换为占位符,例如“No Message”。

无论哪种速度,当您在cellForRow...中构建 tableView 单元格时为self.lastMessageLabel.text分配值时,可能会发生崩溃。检查您在那里使用的 NSString 类类型(isKindOfClass[NSNULL class]),看看是否有帮助。

于 2014-12-13T20:01:28.563 回答
0

@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 ://stackoverflow.com/a/16702060/1603234

于 2014-12-09T08:32:20.507 回答