objective C 中的单例和静态变量访问

Singelton and Static variable access in objective C

我有一个 class City 并且城市列表存储在 Plist 文件中。我只想从文件中加载城市一次,并从共享实例访问城市的 NSArray。

我想要的*

我想要这种行为

/* here if the array cities is nil just load it from plist if not use    the existent array */
City* myCity = [City getCityById:@"1"]; 

还有

/* inside instance method initWithId I should have access to the loaded array of 
 cities or load it one time */

City *aCity = [[City alloc]initWithId:@"4"]

我试过的:

City.h

@interface City : NSObject

@property                     NSInteger  cityId; // instance variable
@property (strong, nonatomic) NSString   *name; // instance variable
@property (strong, nonatomic) CLLocation *location; // instance variable

@property (strong, nonatomic) NSArray    *cities; // want it to act like a Class variable

-(id) initWithDictionary: (NSDictionary *) dictionay; // instance method
-(id) initWithCityId: (NSDictionary *) cityId; // instance method

+(instancetype)sharedInstance; // Singleton object
+(City*) getCityById:(NSString*) id; // the file need to be loaded! 

@end

City.m

@implementation City

// This method load all cities from a plist file

-(void)loadCitiesFromPlist
{
    NSMutableArray *citiesArray = [NSMutableArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"cities" ofType:@"plist"]]; 
    self.cities = citiesArray;
}

+ (instancetype) sharedInstance
{
    // structure used to test whether the block has completed or not
    static dispatch_once_t p = 0;

    // initialize sharedObject as nil (first call only)
    __strong static id _sharedObject = nil;

    // executes a block object once and only once for the lifetime of an application
    dispatch_once(&p, ^{
        _sharedObject = [[self alloc] init];
       [_sharedObject loadCitiesFromPlist];

    });

    // returns the same object each time
    return _sharedObject;
}

+(City*) getCityById:(NSString*)id
{
  // can't access the cities array
}
@end

问题:

注意:城市对象的实例化会发生很多次,因为我有用户,每个用户都属于一个城市,但同时我想有一个共享实例(Singleton)来管理负载文件一次并处理使用 getCityByIdgetIdOfCityByName

等城市数组的 class 方法

查看 NSObject 中的 +(void)initializeLink

任意Class调用一次。在这里您可以将列表加载到静态数组中并在每个实例中使用它。

或者考虑这样的方法:SO answer

解法:

使用方法 + (void)initialize : Apple Documentation 我们将变量声明为 static

City.m

#import "City.h"

static NSArray *cities = nil;

@implementation City

+ (void)initialize
{
    if (self == [City self])
    {
        if (!cities)
        { 
            cities = [self loadCitiesFromPlist];
        }
    }
}

-(id) initWithDictionary: (NSDictionary *) dictionay
{
    self = [super init];
    // convert the NSDictionary to City object
    return self;
}


// This method load all cities from the file

+(NSArray *) loadCitiesFromPlist
{
    NSLog(@"loadCitiesFromPlist");

    NSMutableArray *citiesArray = [NSMutableArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"cities" ofType:@"plist"]];

    NSMutableArray *citiesObjectsArray = [[NSMutableArray alloc] init];

    for (NSDictionary *cityDict in citiesArray)
    {
        [ citiesObjectsArray addObject: [[City alloc]initWithDictionary:cityDict]] ;
    }

   return citiesObjectsArray;
}

+(City*) getCityById:(NSString *) cityId
{

    NSUInteger barIndex = [cities indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {

        City* city = (City*) obj;

        if(city.cityId == [cityId intValue])
        {
            *stop = YES;
            return YES;
        }
        return NO;
    }];


    if (barIndex != NSNotFound)
    {
       return  [cities objectAtIndex:barIndex];
    }
    else
    {
        return nil;
    }

}

+(NSArray*) getAllCitiesNames
{
    NSMutableArray *citiesNames =[[NSMutableArray alloc] init];

    for(City* city in cities)
    {
        [citiesNames addObject:city.name];
    }

    return citiesNames;
}

@end

More Information in this SO answer