Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Try to change variable in singleton but it stays nullable

Tags:

objective-c

Just started programming on objective-c and now i have issue with which can't deal by myself. I'm receiving data from asynchronous request and try to delver it to singleton, but it's not changed.

This is where i'm trying to store my data
Data.h

#import <Foundation/Foundation.h>
@interface Data : NSObject
@property (nonatomic, strong) NSDictionary *products;
-(void)setProducts:(NSDictionary *)value;
@end

Data.m

#import "Data.h"

@implementation Data

+(Data *)sharedInstance
{
    static Data *_sharedInstance = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _sharedInstance = [[Data alloc] init];
    });
    return _sharedInstance;
}

- (id)init {
    self = [super init];
    if ( self )
    {
        _products = [[NSDictionary alloc] init];
    }
    return self;
}

@end

This is the class, where i'm receiving data from server:
ConnectionService.m

- (void)getProductsWithCompletion:(void (^)(NSDictionary *products))completion
{
    NSString *urlString = [NSString stringWithFormat:@"serverurl", [[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];
}

This is the class where i'm calling request and try to deliver it to singleton:
viewController.m

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:YES];
    [[ConnectionService instance] getProductsWithCompletion:^(NSDictionary *products) {
        [Data sharedInstance].products = products;
        NSLog(@"products: %@", [[Data sharedInstance] products]);//all is working, products contains data
    }];
    // checking received data 
    NSDictionary *tmp = [[Data sharedInstance] products];
    NSLog(@"tmp: %@", tmp); //now it's null
}
like image 315
Ookey Avatar asked Dec 14 '25 15:12

Ookey


2 Answers

The issue is the fact that the request is asynchronous and things aren't happening in the order you expect:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:YES];
     [[ConnectionService instance] getProductsWithCompletion:^(NSDictionary *products) {
        // (2)
        [Data sharedInstance].products = products;
        NSLog(@"products: %@", [[Data sharedInstance]products]);//all is working, products contains data
    }];


    // (1)
    NSDictionary *tmp = [[Data sharedInstance]products];
    NSLog(@"tmp: %@", tmp); //now it's null
}

In the code you posted, (1) will happen before (2). That's because (2) is part of the completion block and is set to run once the network request has completed and all the data has been parsed and is ready to use. While that asynchronous request is prepared and run in a background thread, the main thread ((1)) continues and executes before the request has taken place.

To resolve the issue, move your logging into the completion routine, or simply remove (1).

like image 142
trojanfoe Avatar answered Dec 16 '25 23:12

trojanfoe


Another way is to use protocol, to notify your completion block is finished.So that you can simply do:

[[ConnectionService instance] getProductsWithCompletion:^(NSDictionary *products) {
       if(self.delegate){
               [self.delegate  myNotifyMethod:products];
         }

    }];

and your protocol method:

-(void)myNotifyMethod:(NSDictionary *)items{
           [Data sharedInstance].products = products;
            NSLog(@"products: %@", [[Data sharedInstance]products]);
  }

You can declare the protocol as:

@protocol MyProtocol <NSObject>

- (void)myNotifyMethod: (NSDictionary *)items;

@end

and set the delegate property as:

 @property (nonatomic, weak) id<MyProtocol> delegate;
like image 44
Teja Nandamuri Avatar answered Dec 16 '25 22:12

Teja Nandamuri



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!