Как “фальсифицировать” ivars в категории Obj-C (iPhone)

Если я понимаю Ваш вопрос, Вы хотите сослаться на членские переменные/свойства в своем объекте AppDelegate? Самый простой путь состоит в том, чтобы использовать [[UIApplication sharedApplication] делегата] для возврата ссылки на объект.

, Если у Вас есть свойство, названное окном, Вы могли бы сделать это:

UIWindow   *mainWindow = [[[UIApplication sharedApplication] delegate] window];
//do something with mainWindow
6
задан Community 23 May 2017 в 11:47
поделиться

4 ответа

objc_setAssociatedObject () и друзья были добавлены в iPhone OS 3.1, поэтому, если у вас есть возможность настроить таргетинг только на устройства 3.1+, вы фактически можете сделать то же самое, что и на Snow Leopard ...

Если вы не можете, вы можете создать статический словарь ассоциаций и исправить метод освобождения NSObjects. По различным техническим причинам это решение не может работать корректно при наличии GC (поэтому Apple добавила ассоциативный материал), но поскольку iPhone не поддерживает GC, это не проблема.

Если вы только начинаете поработайте над этим проектом, я настоятельно рекомендую использовать функции времени выполнения и настроить таргетинг на 3.1 плюс, но если это не вариант, то вот пример того, как вы это делаете.

LGAssociativeStorage.h:

#import <pthread.h>
#import <Foundation/Foundation.h>

@interface NSObject (LGAssociativeStorage)
@property (retain) id associatedObject;
@end

LGAssociativeStorage. mm

#import <objc/runtime.h>
#import "LGAssociativeStorage.h"

/* We are using STL containers because:
   1) Using Objective C containers can cause deallocs which cause recursion issues
   2) STL containers are high perf containers that don't introduce external code dependencies
   Ideally one could include a thread safe map implementation, but I don't need one currently
*/

#include <map>

typedef std::map<id,id> idMap_t;
typedef std::pair<id,id> idPair_t;

static NSMutableDictionary * data = nil;
static pthread_mutex_t data_lock = PTHREAD_MUTEX_INITIALIZER;
static IMP gOriginalNSObjectDealloc = nil;
static idMap_t  associatedObjectMap;

static
void removeAssociatedObjectFromMap(id self) {
  idMap_t::iterator iter = associatedObjectMap.find(self);
    if( iter != associatedObjectMap.end() ) {
        [iter->second release];
        associatedObjectMap.erase(iter);
    }
}

static
id newNSObjectDealloc(id self, SEL deallocSelector, ...) {
    pthread_mutex_lock(&data_lock);
    removeAssociatedObjectFromMap(self);
    pthread_mutex_unlock(&data_lock);
    return gOriginalNSObjectDealloc(self, deallocSelector);
}

static void initIfNecessary(void) {
    if (!data) {
        data = [[NSMutableDictionary alloc] init];

        // The below line of code is abusive... in the future the Objective C runtime will use it as evidence
        // that I am an unfit software engineer and take custody of all my code
        gOriginalNSObjectDealloc = class_replaceMethod([NSObject class], @selector(dealloc), newNSObjectDealloc, "v@:");
    }
}



@implementation NSObject (LGAssociativeStorage)

- (id) associatedObject {
    id retval = nil;
    pthread_mutex_lock(&data_lock);
    initIfNecessary();
    idMap_t::iterator iter = associatedObjectMap.find(self);
    if( iter != associatedObjectMap.end() ) {
        retval = iter->second;
    }
    pthread_mutex_unlock(&data_lock);
    return retval;
}

- (void) setAssociatedObject:(id)object_ {
    pthread_mutex_lock(&data_lock);
    initIfNecessary();
    removeAssociatedObjectFromMap(self);
    [object_ retain];
    associatedObjectMap.insert(idPair_t(self, object_));
    pthread_mutex_unlock(&data_lock);   
}

@end
13
ответ дан 8 December 2019 в 13:01
поделиться

Вы всегда можете хранить их в синглтоне.

3
ответ дан 8 December 2019 в 13:01
поделиться

Нет хороших способов сделать это в общей категории.

Вы можете легко добавлять данные для объекта, имея глобальный NSMutableDictionary, который сопоставляет любой произвольный объект NSObject с любыми данными, которые вы хотите . Проблема в том, что нет способа узнать, когда объект освобожден, поэтому вы не можете сказать (в общем), когда данные становятся устаревшими.

Единственный общий способ решить эту проблему - использовать swizzling для замены метода dealloc NSObject чтобы сообщить об освобождении объекта и освободить связанные данные. Я уверен, что кто-то сделал это, но это такой отвратительный прием, что его было бы очень трудно рекомендовать в качестве допустимого подхода.

Теперь, если у ваших объектов в вопросах есть другой способ мониторинга жизненного цикла (например, некоторое освобождение крючок, например, какой-то метод делегата objectWillClose),

2
ответ дан 8 December 2019 в 13:01
поделиться

Я добавлю ответ.

Я нашел исходное сообщение в блоге , оно было от Стива Дегутиса.

В основном это включает замену методов NSObject на valueForUndefinedKey: , setValue: ForUndefinedKey: ] и dealloc . Затем используйте статический Словарь для хранения любых неопределенных ключей.

Примерно так же неприятно и забавно, как решение Луи.

0
ответ дан 8 December 2019 в 13:01
поделиться