繁体   English   中英

iOS 8可以运行,但iOS 7会因-[NSNull长度]而崩溃:无法识别的选择器已发送到实例

[英]iOS 8 works but iOS 7 crashes with -[NSNull length]: unrecognized selector sent to instance

我一直在寻找答案,但是仍然无法解决问题。 -[NSNull长度]:无法识别的选择器发送到实例,而此[NSNull长度]:无法识别的选择器发送到实例0x43fe068没有帮助。

我正在使用一个具有Parse后端的聊天应用程序,并且我遇到了一个时间戳问题,聊天消息显示为乱序,因此我使用Databrowser从我的Parse数据库中删除了乱序的行。 当我测试该应用程序时,这似乎可以解决同时运行iOS 8的iPhone 6 Plus和iPhone 6模拟器上的问题。但是,当在运行iOS 7的iPhone 5s上打开同一聊天室时,该应用程序会崩溃,并与以下错误。

-[NSNull length]: unrecognized selector sent to instance

我不知道为什么删除一行会导致这种情况发生,为什么只在iOS 7上? 我设置了“所有异常”断点,这是违规行以及屏幕截图。

    self.lastMessageLabel.textColor = [UIColor redColor];

在此处输入图片说明

即使我注释掉上面的行,我仍然会收到NSNull length崩溃的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)的NSNullSafe https://github.com/nicklockwood/NullSafe ,它允许打开私人收件箱而不会崩溃,并且使我摆脱了NSNull Length错误,但我认为这只是掩盖了问题,我仍然不愿意不知道为什么它在iOS 8上没有崩溃,但在iOS 7上却崩溃了。

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

@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

其他两个答案是正确的-这不是OS版本的问题,而是您正在传递NULL值并且没有捕获该值。

您在异常中捕获的行:

 self.lastMessageLabel.textColor = [UIColor redColor];

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM