статические инициализаторы в цели C

Как мне сделать статические инициализаторы в target-c (если я правильно понял термин). В основном я хочу сделать что-то вроде этого:

static NSString* gTexts[] = 
{
    @"A string.",
    @"Another string.",
}

Но я хочу сделать это более похожим на структуру, то есть иметь не только NSString для каждого элемента в этом массиве, но вместо этого NSString плюс один NSArray, который содержит переменный номер MyObjectType, где MyObjectType будет содержать NSString, пару целых чисел и т. д. .


person Joey    schedule 16.02.2011    source источник


Ответы (4)


Поскольку NSArrays и MyObjectTypes являются объектами, размещенными в куче, вы не можете создавать их в статическом контексте. Вы можете объявить переменные, а затем инициализировать их в методе.

Итак, вы не можете сделать:

static NSArray *myStaticArray = [[NSArray alloc] init....];

Вместо этого вы должны сделать:

static NSArray *myStaticArray = nil;

- (void) someMethod {
  if (myStaticArray == nil) {
    myStaticArray = [[NSArray alloc] init...];
  }
}

Это происходит для работы с постоянными строками (@"foo" и т. д.), поскольку они не выделяются в куче. Они жестко закодированы в двоичном коде.

person Dave DeLong    schedule 16.02.2011
comment
Значит, someMethod не может быть просто методом инициализации? - person Ken Wayne VanderLinde; 16.02.2011

Очень важно убедиться, что ваша статическая инициализация является потокобезопасной (доступно в iOS 4.1+)!!!

static NSArray *myStaticArray = nil;

- (void) someMethod {
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    myStaticArray = [[NSArray alloc] init...]
  });
}
person chrish    schedule 30.06.2011
comment
Если это NSObject, почему бы не сделать это в + (void)initialize, если вы определенно собираетесь использовать массив? - person qix; 12.02.2013
comment
Это необходимо только в том случае, если someMethod можно вызвать из нескольких потоков. В самой статической инициализации нет ничего особенного, что требовало бы потокобезопасности. - person Ben; 25.01.2014

вот один из способов, если вы можете жить с переводом objc++:

#import <Foundation/Foundation.h>

namespace { // ok, this storage should preferably be in a function/deferred
    static struct sa { NSString* const s; NSArray* const a; } r = {
      [[NSString alloc] initWithString:@"hello"],
      [[NSArray alloc] initWithObjects:@"w", @"o", @"r", @"l", @"d", @"= =", nil]
    };
}

int main(int argc, const char* argv[]) {
  NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
  NSLog(@"\n\n%@...\n\n...\n%@", r.s, r.a);
  [pool drain];
  return 0;
}
person justin    schedule 16.02.2011

Метод +initialize вызывается автоматически при первом использовании класса, до использования каких-либо методов класса или создания экземпляров.

+ (void) initialize {
  if (self == [MyClass class]) {
    // Once-only initializion
  }
  // Initialization for this class and any subclasses
}

+initialize наследуется подклассами, а также вызывается для каждого подкласса, который не реализует собственную +initialize. Это может быть особенно проблематично, если вы наивно реализуете одноэлементную инициализацию в +initialize. Решение состоит в том, чтобы проверить тип переменной класса.

p.s. Вы никогда не должны вызывать +initialize самостоятельно.

person Zee    schedule 09.01.2015