Глобальные переменные для методов класса - PullRequest
6 голосов
/ 14 декабря 2011

Фон

В Какао Apple часто использует следующую парадигму:

[NSApplication sharedApplication]
[NSNotificationCenter defaultNotificationCenter]
[NSGraphicsContext currentContext]
[NSCalendar currentCalendar]

и т. Д.

Они также иногда используют парадигмуя чувствую, что намного более разборчиво при работе с огромным количеством кода.

NSApp //which maps to [NSApplication sharedApplication]

Цель

Я бы хотел использовать этот вид глобальногопеременная, как в моих собственных классах, так и в расширениях других классов.

MYClassInstance
NSDefaultNotificationCenter
NSCal /* or */ NSCurrentCalendar

и т. д.

Подход "Дух"

#define.Просто #define NSCal [NSCalendar currentCalendar], но, как мы все знаем к настоящему времени, макросы - это зло (или, как они говорят), и это не похоже на правильный способ Cocoa для этого.

Подход Apple

Единственный источник, который я мог найти относительно NSApp, был APPKIT_EXTERN id NSApp;, который не совсем повторный код.Если я не ошибаюсь, весь этот код определяет NSApp как id окружающий мир.К сожалению, бесполезно.

Закрыть, но не совсем

В моих поисках мне удалось найти несколько потенциальных ссылок относительно "глобальных констант", однако такие вещи:

extern NSString * const StringConstant;
*К сожалению, 1038 * ограничены константами времени компиляции и не могут отображаться на необходимый метод класса.

Итог

Мне бы хотелось иметь возможность свернуть свой собственный стиль NSAppглобальные переменные, которые отображаются на методы класса, такие как [NSNotificationCenter defaultNotificationCenter].Это возможно?Если да, то как мне это сделать?

Дальнейшие попытки

Я пытаюсь специально реализовать синглтоны фреймворка следующим образом:

MySingletons.h

//...
extern id NSNotifCenter;
//...

MySingletons.m

//...
+(void)initialize
{
    NSNotifCenter = [NSNotificationCenter defaultCenter];
}
//...

MyAppDelegate.m

//...
#import "MySingletons.h"
//...
//in applicationDidFinishLaunching:
    [MySingletons initialize];
    NSLog(@"%@", NSNotifCenter);
//...

Однако это приводит к ошибке времени компиляции, когда не удается найти символ _NSNotifCenter.

Цель!

В настоящее время я работаю над классом Objective-C для инкапсуляции некоторых фреймворков-фреймворков, о которых я говорил в этом вопросе.Я добавлю сюда информацию о GitHub, когда получу ее.

Ответы [ 2 ]

8 голосов
/ 14 декабря 2011

Забавно, я только что сделал это предложение по другому вопросу.

Вы просто выставляете переменную, которая содержит экземпляр singleton, как саму глобальную. NSApp на самом деле не сопоставляет с sharedApplication вызовом. Это обычный старый указатель; во время запуска приложения он был настроен на , указывающий на тот же экземпляр, который вы получите от этого вызова.

Как и NSApp, вы объявляете переменную для любого файла, который импортирует заголовок:

extern MySingleton * MySingletonInstance;

в заголовке (вы можете использовать APPKIT_EXTERN, если хотите; документы указывают , что он все равно разрешается до extern в ObjC в любом случае).

В файле реализации вы определяете переменную. Обычно переменная, содержащая общий экземпляр, объявляется static, чтобы ограничить его связь с этим файлом. Если вы удалите static, оператор определяет хранилище, которое «повторно объявлено» в заголовке.

Тогда используйте это, как вы делали раньше. Единственное предостережение в том, что вам по-прежнему нужно вызывать свой метод настройки singleton [MySingleton sharedInstance] перед первым использованием глобала, чтобы убедиться, что он инициализирован. -applicationDidFinishLaunching: может быть хорошим кандидатом на место для этого.

Что касается создания указателей на синглтоны фреймворка, вы можете просто спрятать результат [CocoaSingleton sharedInstance] в любую переменную, какую захотите: ивар в классе, который хочет его использовать, локальную переменную или в глобальную переменную, которую вы инициализируете. очень рано в вашей программе через функцию, которую вы пишете.

Дело в том, что это не гарантирует, что не вызовет проблем. За исключением случая NSApp (или если это где-то не задокументировано), на самом деле нет никакой гарантии, что объект, который вы получите от любого данного вызова sharedInstance, останется живым, действительным или полезным после окончания стека вызовов. ,

Это может быть просто паранойей, но я бы посоветовал не делать этого, если только вы не найдете где-нибудь гарантии, что предполагаемые синглтоны, которые вас интересуют , всегда возвращают один и тот же экземпляр. В противном случае вы можете внезапно получить висящий глобальный указатель.

Обращаясь к вашему коду, объявление в вашем заголовке не создает переменную. Вам все еще нужно определение где-то:

// MySingletons.h
// Dear compiler, There exists a variable, NSNotifCenter, whose 
// storage is elsewhere. I want to use that variable in this file.
extern id NSNotifCenter;

// MySingletons.m
// Dear compiler, please create this variable, reserving memory
// as necessary.
id NSNotifCenter;

@implementation MySingletons

// Now use the variable.
// etc.

Если вы создаете синглтон, возможно, вы захотите взглянуть на документацию Apple по синглтонам .

2 голосов
/ 15 декабря 2011

Существующее обсуждение здесь было настолько интригующим, что я провел небольшое исследование и обнаружил то, чего никогда раньше не осознавал: я могу #import файл заголовка из моего собственного проекта в файл .pch проекта (предварительно скомпилированный заголовок),Этот заголовочный файл становится автоматически видимым для всех других файлов класса в моем проекте без усилий с моей стороны.

Так вот примеро том, что я сейчас делаю.В файле .pch, под существующим кодом:

#import "MyIncludes.h"

В MyInclude.h есть два вида вещей, категории и внешние элементы (последние в соответствии с предложением Джоша):

extern NSString* EnglishHiddenKey;
extern NSString* IndexOfCurrentTermKey;

@interface UIColor (mycats)
+ (UIColor*) myGolden;
+ (UIColor*) myPaler;
@end

В MyIncludes.m мы предоставляем определения для удовлетворения всех объявлений из заголовочного файла.Внешние элементы не должны быть определены из какого-либо класса:

#import "MyIncludes.h"

NSString* EnglishHiddenKey = @"englishHidden";
NSString* IndexOfCurrentTermKey = @"indexOfCurrentTerm";

@implementation UIColor (mycats)
+ (UIColor*) myGolden {
    return [self colorWithRed:1.000 green:0.894 blue:0.541 alpha:.900];
}
+ (UIColor*) myPaler {
    return [self colorWithRed:1.000 green:0.996 blue:0.901 alpha:1.000];
}
@end

За исключением части об использовании файла pch для получения волшебной глобальной видимости, это на самом деле ничем не отличается от предложения Джоша.Я публикую его как отдельный ответ (а не просто комментарий), потому что он длинный и требует форматирования, и явный код может кому-то помочь.

(Обратите внимание, что управление памятью отсутствует, потому что яс использованием ARC. Внешние утечки, конечно, но предположительно утечки: они должны жить до тех пор, пока приложение работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...