【问题标题】:NSDictionary to NSString not workingNSDictionary 到 NSString 不起作用
【发布时间】:2023-03-09 03:30:01
【问题描述】:

我对原生 iOS 编程完全陌生,对此有一些大大小小的问题。我的问题之一如下:

我想从服务器检索user_id,所以我使用NSURLSession。我的代码如下所示:

NSString *phone_nr = @"00436604056720";
__block NSString *user_id;

NSURLSession *session_json = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session_json dataTaskWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://localhost/picshare/index.php?phone_nr=%@", phone_nr]] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
   NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
   NSLog(@"%@", json);

   user_id = @"%@",[json objectForKey:@"user_id"];
}];

[dataTask resume];

代码工作正常(我检索到正确的user_idphone_nr)但我不能alertuser_id...但是当我NSLog 它时,它工作得很好。问题是我不能在函数之外的任何地方使用user_id 变量。

UIAlertView 看起来像这样:

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Headline"
                                                    message:user_id
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];

【问题讨论】:

  • 我希望你已经调用了[alert show]?
  • 来自文档:dataTaskWithURL:completionHandler: 为指定的 URL 创建一个 HTTP GET 请求,然后在完成时调用一个处理程序。
  • user_id = @"%@",[json objectForKey:@"user_id"];是一个“逗号表达式”。在初学者的 C 书籍中查找逗号表达式是什么。我敢打赌你不想在这里使用一个。

标签: ios objective-c nsstring nsdictionary nsurlsession


【解决方案1】:
NSString *phone_nr = @"00436604056720";

NSURLSession *session_json = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session_json dataTaskWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://localhost/picshare/index.php?phone_nr=%@", phone_nr]] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
   NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
   NSLog(@"%@", json);

   NSString *user_id = [json objectForKey:@"user_id"];
   dispatch_async(dispatch_get_main_queue(), ^{
   UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Headline"
                                                message:user_id
                                               delegate:nil
                                      cancelButtonTitle:@"OK"
                                      otherButtonTitles:nil];
   [alert show];
  });
}];

[dataTask resume];

不要声明 _block 变量。

【讨论】:

  • “发布”版本当然应该检查 HTTP 状态代码和响应的 MIME 类型之前向解析器提供从服务器发送的(可能的)HTML在出现问题的情况下。 ;)
【解决方案2】:

项目:

  • 我不确定我或编译器是否解析了这一行:

      user_id = @"%@",[json objectForKey:@"user_id"];
    
  • user_id 只会在调用块之后被设置,这不会与代码“一致”。您如何/何时启动警报?

  • user_id 也有自动释放的风险。触发警报时对象是否有效?


附录

回复@CouchDeveloper的评论,给定

NSDictionary *d = @{@"compiler": @"Apple LLVM 5.1"};
NSString *s = @"%@", [d objectForKey:@"compiler"];

我的编译器生成

<path elided>: error: expected identifier or '('
NSString *s = @"%@", [d objectForKey:@"compiler"];
                     ^
<path elided>: error: missing '[' at start of message send expression
NSString *s = @"%@", [d objectForKey:@"compiler"];
                      ^
                      [
<path elided>: error: expected ']'
NSString *s = @"%@", [d objectForKey:@"compiler"];
                                                 ^
<path elided>: note: to match this '['
NSString *s = @"%@", [d objectForKey:@"compiler"];
                     ^
3 errors generated.

您的编译器可能不同。

【讨论】:

  • 编译器解析它而不会出错。请查找“逗号运算符”。不过,这可能是 OP 代码中的一个错字。 user_id 将在块执行期间设置。实际上,当这种情况发生时,__block 变量将存在于堆上。访问数组返回的对象是否自动释放也无关紧要。
  • @CouchDeveloper 请查收。我上面的回复。
【解决方案3】:

使用这个。我认为你没有使用[alert show];

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Headline"
                                                    message:user_id
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
[alert show];

【讨论】:

    【解决方案4】:

    我想我得到了你的解决方案->

    First for->“问题是我不能在函数之外的任何地方使用user_id变量”

    Solution-> 使用 NSUserDefault 从块中保存用户 id,或者您可以使用属性变量来存储 user_id

    [[NSUserDefaults standardUserDefaults]
        setObject:valueToSave forKey:@"USER_ID"];
    

    或者

    @property (retain, nonatomic) NSString *user_id;
    

    第二次->“但我无法提醒user_id...”

    Solution-> 在你的块内执行此操作以调用 UIAlert 视图

    [self performSelectorOnMainThread:@selector(showAlertWithTitle:)
                               withObject:user_id
                            waitUntilDone:YES];
    
    - (void)showAlertWithTitle:(NSString *)t
    {
        [[[[UIAlertView alloc] initWithTitle:t
                                     message:nil
                                    delegate:nil
                           cancelButtonTitle:@"OK"
                           otherButtonTitles:nil
        ] autorelease] show];
    }
    

    【讨论】:

      【解决方案5】:

      正如其他人提到的,您可以使用UIAlertView 向用户显示用户ID。但是,我认为这不是您的主要问题。我不相信您完全掌握了变量范围或 c 块。我们来看一个简单的例子:

      __block NSString *myID = nil;
      [someObject getMyID:^(NSString *returnedID){
          myID = returnedID;
          NSLog(@"%@", myID); //myID has a value here
      }];
      
      NSLog(@"%@", myID); //myID is "NULL" here
      

      所以这里发生的情况是,您正在向someObject 传递一个代码块,它可以使用它在获取它后返回returnedID。这通常是异步完成的,这意味着调用getMYID 的方法/函数不会等待该值。该方法中的其余语句在之前处理,someObject 可以返回returnedID 并将其传递给您给它的块。这意味着myID 将被设置,直到创建它的方法完成之后很久。因为myID 是在函数内部创建的,所以它的作用域是在该方法完成时完成的。但是,myID 将继续存在,因为您传递给someObject 的块保留了对它的引用。一旦该块被执行,myID 就会被销毁并且值会丢失。

      很可能,您想要的是一个实例变量,它可以在方法返回后继续存在。例如,您可能有一个属性:

      @property (strong) NSString *myID;
      

      现在在你的实现中你可以这样做:

      [someObject getMyID:^(NSString *returnedID){
          self.myID = returnedID;
      }];
      

      现在someObject 返回的值将保留,因为它被分配给一个实例变量,只要调用getMyID 的对象持续存在,该实例变量的作用域就会持续存在。请注意,它实际上直到稍后才会设置(每当someObject 开始调用您传递的块时)。

      如果您只需要在方法调用中保留该值,您可能只需将该代码放在传递给someObject getMyID 的块中:

      [someObject getMyID:^(NSString *returnedID){
          //Do stuff with returnedID;
      }];
      

      其他人提到了dispatch_async(dispatch_get_main_queue(), ^{ //do stuff });。原因是您传递给someObject 的代码块可能不会在主线程上调用,并且任何访问UI 的代码(如UIAlertView)都必须在主线程上调用。 dispatch_async 将允许您这样做。

      【讨论】:

      • 感谢您的回答。我创建了 user_id 属性并将 id 返回给它,但我无法访问该函数 outside 的变量。我实际上想在函数中分配它,然后我想在其他地方使用它。我希望你明白我的意思。
      • 您在函数内创建的任何变量永远不能在函数外使用。函数完成后将被销毁。您必须在可以访问的函数之外创建一个变量(如实例变量)。您传递给另一个函数的任何块(例如:[object doBlock:^(parameters, ...){ //code }])都将在调用它的函数外部执行。函数可以(但不是必须)异步运行块,这意味着代码块将在调用它的函数完成后运行一段时间。
      • @JohnBrunner 您似乎缺少一些关于变量、范围、块和objective-c在一般工作中的基本知识。这是关于 c“块”的一个很好的教程:Blocks Tutorial。另外,这里有一个关于目标 c 的一般教程:Objective-c Tutorial。您可以使用这些来全面了解 Objective-c 使用变量、范围和块的工作。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-06
      相关资源
      最近更新 更多