尝试从 objects[1]' 插入 NIL 对象

attempt to insert nil object from objects[1]'

提问人:programcode 提问时间:3/28/2021 最后编辑:programcode 更新时间:3/29/2021 访问量:276

问:

我想通过选项卡栏控制器显示 ChatViewController。应用的当前初始视图是加载 ChatViewController 的 NavigationController。加载 ChatViewController 时,它会检查是否调用了“joinedchat”方法。如果没有,它会显示 LoginViewController 以允许用户对 ChatViewController 进行身份验证。当用户进行身份验证时,LoginViewController 将关闭。

LoginViewController 和 ComposeViewController 是显示在 ChatViewController 顶部的模式视图控制器。

我想在情节提要的稍后时间点访问此 ChatViewController,同时将其保留为 rootviewcontroller,以便它仍然可以保留它用于类的数据模型,以预期它使用的方法。$_POST

如果尚未调用,我没有显示 LoginViewController,而是显示不同的视图控制器。大约 4 个视图控制器之后,在用户执行不同的进程后,我使用选项卡栏控制器再次访问 LoginViewController。当我尝试调用 postUpdateRequest 方法来访问 ChatViewController 时,应用程序崩溃,调试器中显示输出:joinedchat

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[1]'

我怀疑这是因为该应用程序使用严格的数据模型来设置 snd 存储用户将从 LoginViewController 通过 .有谁知道使用此数据对用户进行身份验证的任何方法?postJoinRequest

AppDelegate.m - didRegisterForRemoteNotificationsWithDeviceToken

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{

UINavigationController *navigationController = (UINavigationController*)_window.rootViewController;
ChatViewController *chatViewController = (ChatViewController*)[navigationController.viewControllers objectAtIndex:0];

DataModel *dataModel = chatViewController.dataModel;
NSString* oldToken = [dataModel deviceToken];

NSString* newToken = [deviceToken description];
newToken = [newToken stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
newToken = [newToken stringByReplacingOccurrencesOfString:@" " withString:@""];

NSLog(@"My token is: %@", newToken);

[dataModel setDeviceToken:newToken];

if ([dataModel joinedChat] && ![newToken isEqualToString:oldToken])
{
    [self postUpdateRequest];
}
 
}

AppDelegate.m - PostUpdateRequest (英文)

- (void)postUpdateRequest
{
UINavigationController *navigationController = (UINavigationController*)_window.rootViewController;
ChatViewController *chatViewController = (ChatViewController*)[navigationController.viewControllers objectAtIndex:0];

DataModel *dataModel = chatViewController.dataModel;

NSDictionary *params = @{@"cmd":@"update",
                         @"user_id":[dataModel userId],
                         @"token":[dataModel deviceToken]};

AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:ServerApiURL]];
[client
 postPath:@"/api.php"
 parameters:params
 success:nil failure:nil];
}

DataModel.m - 初始值设定项

+ (void)initialize
{
if (self == [DataModel class])
{
    // Register default values for our settings
    [[NSUserDefaults standardUserDefaults] registerDefaults:
        @{NicknameKey: @"",
            SecretCodeKey: @"",
            JoinedChatKey: @0,
            DeviceTokenKey: @"0",
            UserId:@""}];
}
}

DataModel.m - 用户 Id

- (NSString*)userId
{
NSString *userId = [[NSUserDefaults standardUserDefaults] stringForKey:UserId];
if (userId == nil || userId.length == 0) {
    userId = [[[NSUUID UUID] UUIDString] stringByReplacingOccurrencesOfString:@"-" withString:@""];
    [[NSUserDefaults standardUserDefaults] setObject:userId forKey:UserId];
}
return userId;
}

LoginViewController.h (更新)

@class DataModel;

// The Login screen lets the user register a nickname and chat room
@interface LoginViewController : UIViewController
@property (nonatomic, assign) DataModel* dataModel;
@property (nonatomic, strong) AFHTTPClient *client;
@end

LoginViewController.m - postJoinRequest 和 loginAction

- (void)postJoinRequest
{
MBProgressHUD* hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = NSLocalizedString(@"Connecting", nil);

NSDictionary *params = @{@"cmd":@"join",
                         @"user_id":[_dataModel userId],
                         @"token":[_dataModel deviceToken],
                         @"name":[_dataModel nickname],
                         @"code":[_dataModel secretCode]};

[_client postPath:@"/api.php"
                          parameters:params
                             success:^(AFHTTPRequestOperation *operation, id responseObject) 
{
                                 
                                 if ([self isViewLoaded]) {
                                     [MBProgressHUD hideHUDForView:self.view animated:YES];
                                     
                                     if([operation.response statusCode] != 200) {
                                         ShowErrorAlert(NSLocalizedString(@"There was an error communicating with the server", nil));
                                     } else {
                                         [self userDidJoin];
                                     }
                                 }
                             } failure:^(AFHTTPRequestOperation *operation, NSError *error) 
{
                                 if ([self isViewLoaded]) {
                                     [MBProgressHUD hideHUDForView:self.view animated:YES];
                                     ShowErrorAlert([error localizedDescription]);
                                 }
                             }];
}

- (IBAction)loginAction
{
if (self.nicknameTextField.text.length == 0)
{
    ShowErrorAlert(NSLocalizedString(@"Fill in your nickname", nil));
    return;
}

if (self.secretCodeTextField.text.length == 0)
{
    ShowErrorAlert(NSLocalizedString(@"Fill in a secret code", nil));
    return;
}

[self.dataModel setNickname:self.nicknameTextField.text];
[self.dataModel setSecretCode:self.secretCodeTextField.text];

// Hide the keyboard
[self.nicknameTextField resignFirstResponder];
[self.secretCodeTextField resignFirstResponder];

[self postJoinRequest];
}

ChatViewController.h (更新)

#import "ComposeViewController.h"

@class DataModel;

// The main screen of the app. It shows the history of all messages that
// this user has sent and received. It also opens the Compose screen when
// the user wants to send a new message.
@interface ChatViewController : UITableViewController <ComposeDelegate>

@property (nonatomic, strong, readonly) DataModel* dataModel;

@end

更新终端输出

enter image description here

iOS Objective-C iPhone Cocoa-Touch AfNetworking

评论

1赞 Larme 3/28/2021
当它崩溃时,你能显示完整的调用堆栈吗?即,控制台中应该有更多。
1赞 Larme 3/29/2021
但我倾向于说这可能是罪魁祸首。你能在设置字典之前打印它吗?并找出哪一个真正让它崩溃,因为它被使用了两次?当它崩溃时,你能显示完整的调用堆栈吗?即,控制台中应该有更多。@"user_id":[dataModel userId]
0赞 programcode 3/29/2021
谢谢。我附议。我也怀疑userId。这一次,我将 datamodel 类和 AFHTTP 客户端传递给每个视图,以便它可以在稍后的屏幕上尝试登录之前访问 api 中使用的 $_POST 数据。祈祷。
1赞 Larme 3/29/2021
在控制台中复制/粘贴错误消息,而不是屏幕截图。那时它可能已经满了。并在使用前打印值。不相关,但一个大问题:您从 to 获取令牌的方式不适用于 iOS 13+。[dataModel userId]NSDataNSStringNSString* newToken = [deviceToken description];
0赞 programcode 3/30/2021
TY又是m8。我倾向于使用不同的根视图控制器。希望编辑 和 方法更容易,以便在从 .didRegisterForRemoteNotificationUpdateappdelegate.mpostJoinRequestLoginViewControlelr

答: 暂无答案