尝试将数据从异步调用传输到另一个类

时间:2016-03-04 14:50:43

标签: ios objective-c

我知道这是一个愚蠢的问题,但我无法找到解决方案。

这是我的代码:
ConnectionService.h。

#import "LaunchScreenViewController.h"
@interface ConnectionService : NSObject

-(void)getsFeaturedProducts;

@end

ConnectionService.m

-(void)getsFeaturedProducts {
NSString *urlString = [NSString stringWithFormat:@"my-url",[[AppDelegate instance] getUrl]];
    NSURL *url = [NSURL URLWithString:urlString];

    NSURLSessionDataTask *getData = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData* data, NSURLResponse *response, NSError* error){
        NSString* rawJson = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSDictionary *value = [rawJson JSONValue];
        _featuredProducts = [[NSDictionary alloc]initWithDictionary:value];
        NSLog(@"Featured products: %@", _featuredProducts);//not empty

        LaunchScreenViewController *lsvc = [[LaunchScreenViewController alloc]init];
        lsvc.featuredProducts = self.featuredProducts;
NSLog(@"Featured products: %@", lsvc.featuredProducts);//not empty
    }];
    [getData resume];
}

LaunchScreenViewController.h

#import "ConnectionService.h"

@interface LaunchScreenViewController : UIViewController
@property(nonatomic,strong) NSDictionary *featuredProducts;
@end

LaunchScreenViewController.m

- (void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:YES];

    ConnectionService *connectionService = [[ConnectionService alloc]init];
    [connectionService refreshProducts];

    self.featuredProducts = [[NSDictionary alloc]init];
    NSLog(@"featuredProducts: %@", self.featuredProducts);//empty
    NSArray *keys = [[NSArray alloc]initWithArray:[self.featuredProducts allKeys]];
    NSLog(@"All featured product keys: %@", keys);
}

我做错了什么?

P.S。编程目标-c少于一个月,所以是的...谢谢-rep。

4 个答案:

答案 0 :(得分:1)

你认为这个异步问题是错误的 - 但你并不遥远。以下是您的代码现在正在做的事情:

  1. 创建了一个LaunchScreenViewController实例。

  2. LaunchScreenViewController的实例创建了ConnectionService的实例

  3. ConnectionService查询异步数据

  4. 返回数据后,它会创建LaunchScreenViewController的 BRAND NEW 实例并将其传递给数据。

  5. 您检查原始的LaunchScreenViewController是否有数据,但没有 - 它转而使用新实例。

  6. 您希望将数据传回原始的LaunchScreenViewController。有几种方法可以做到这一点。我会告诉你一个并链接到第二个。

    让我们举例说明如何通过NSNotificationCenter将数据传回原始控制器:

    LaunchScreenViewController.m

    - (void)viewDidLoad:(BOOL)animated{
        //Your current code....
    
        [[NSNotificationCenter defaultCenter] addObserver:self
        selector:@selector(receiveConnectionData:) 
        name:@"ConnectionDataReceived"
        object:nil];
    
    }
    
    - (void) receiveTestNotification:(NSNotification *) notification
    {
        // [notification name] should always be @"ConnectionDataReceived"
        // unless you use this method for observation of other notifications
        // as well.
    
        if ([[notification name] isEqualToString:@"ConnectionDataReceived"]){
    
            self.featuredProducts = [[NSDictionary alloc]init];
            NSLog(@"featuredProducts: %@", self.featuredProducts);//empty
            NSArray *
            NSArray *keys = [[NSArray alloc]initWithArray:[notification.object allKeys]];
            NSLog(@"All featured product keys: %@", keys);
            NSLog (@"Successfully received the test notification!");
        }
    }
    

    在您的ConnectionService.h

    -(void)getsFeaturedProducts {
        NSString *urlString = [NSString stringWithFormat:@"my-url",[[AppDelegate instance] getUrl]];
        NSURL *url = [NSURL URLWithString:urlString];
    
        NSURLSessionDataTask *getData = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData* data, NSURLResponse *response, NSError* error){
            NSString* rawJson = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSDictionary *value = [rawJson JSONValue];
            _featuredProducts = [[NSDictionary alloc]initWithDictionary:value];
            NSLog(@"Featured products: %@", _featuredProducts);//not empty
    
            //Pass the NSDictionary back to the ORIGINAL LaunchViewController
            [[NSNotificationCenter defaultCenter]  postNotificationName:@"ConnectionDataReceived"  _featuredProducts];
    }];
    [getData resume];
    

    }

    注意:您也可以使用Delegate来完成此操作,这更复杂但更强大。你可以在这里找到Chris Mills的一个很好的教程:https://coderchrismills.wordpress.com/2011/05/05/basic-delegate-example/

答案 1 :(得分:0)

您需要将结果返回给控制器。

您需要做的是在您的 - (void)getsFeaturedProducts函数中添加一个完成块,然后在返回结果后立即调用它传回结果。

在同一个功能中,您可以使用正确的数据重新加载视图。

<强>服务

PYSPARK_PYTHON

<强>控制器

-(void)getsFeaturedProducts:(void (^)(NSDictionary *featuredProducts))completionHandler {
      NSString *urlString = [NSString stringWithFormat:@"my-url",[[AppDelegate instance] getUrl]];
NSURL *url = [NSURL URLWithString:urlString];

      NSURLSessionDataTask *getData = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData* data, NSURLResponse *response, NSError* error){
          NSString* rawJson = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
          NSDictionary *featuredProducts = [rawJson JSONValue];
          completionHandler(featuredProducts);
      }];
     [getData resume];
}  

}

答案 2 :(得分:0)

您的代码无效,因为使用LaunchScreenViewController创建的alloc init实例不是在Storyboard / XIB文件中创建的实例。

从另一个类异步检索数据的推荐方法是完成处理程序。

ConnectionService.m 中使用完成处理程序实现该方法,并在.h文件中相应地声明它。

- (void)getsFeaturedProductsWithCompletion:(void (^)(NSDictionary *products))completion
{
  NSString *urlString = [NSString stringWithFormat:@"my-url",[[AppDelegate instance] getUrl]];
  NSURL *url = [NSURL URLWithString:urlString];

  NSURLSessionDataTask *getData = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData* data, NSURLResponse *response, NSError* error){
    NSString* rawJson = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSDictionary *value = [rawJson JSONValue];
    completion(value);
  }];
  [getData resume];
}

附注:强烈建议在数据任务中添加错误处理!!

LaunchScreenViewController.h 中声明ConnectionService实例的属性

#import "ConnectionService.h"

@interface LaunchScreenViewController : UIViewController
@property(nonatomic,strong) NSDictionary *featuredProducts;
@property(nonatomic,strong) ConnectionService *connectionService;
@end

LaunchScreenViewController.m 中调用方法

- (void)viewDidAppear:(BOOL)animated{
  [super viewDidAppear:YES];

  connectionService = [[ConnectionService alloc]init];
  [connectionService getsFeaturedProductsWithCompletion:^(NSDictionary *products) {
    self.featuredProducts = products;
    NSLog(@"featuredProducts: %@", self.featuredProducts);//empty
    NSArray *keys = [[NSArray alloc]initWithArray:[self.featuredProducts allKeys]];
    NSLog(@"All featured product keys: %@", keys);
    connectionService = nil; // release the connectionService instance if needed
  }];
}

答案 3 :(得分:-1)

-(void)getsFeaturedProducts {
NSString *urlString = [NSString stringWithFormat:@"my-url",[[AppDelegate instance] getUrl]];
NSURL *url = [NSURL URLWithString:urlString];
NSURLSessionDataTask *getData = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData* data, NSURLResponse *response, NSError* error){
    dispatch_async(dispatch_get_main_queue(), ^{
        NSString* rawJson = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSDictionary *value = [rawJson JSONValue];
        _featuredProducts = [[NSDictionary alloc]initWithDictionary:value];
        NSLog(@"Featured products: %@", _featuredProducts);//not empty

        LaunchScreenViewController *lsvc = [[LaunchScreenViewController alloc]init];
        lsvc.featuredProducts = self.featuredProducts;
        [[[UIApplication sharedApplication] keyWindow] setRootViewController:lsvc];
    })

}];
[getData resume];
}