Прослушивание переменной в другом файле?

Как я уже сказал, совершенно новый для Objective-C. Однако у меня есть несколько лет опыта программирования, и я быстро учусь.

Общая проблема: я хочу прослушать переменную внутри другого файла, а затем выполнить определенное действие в ответ на изменения этой переменной.

Конкретная проблема: я хочу изменить способ отображения сигнала Wi-Fi на iPhone. В настоящее время он имеет 4 состояния, но я хочу, чтобы у него было 8 состояний. Я надеюсь каким-то образом прослушивать (или периодически читать) переменную wifiSignalStrengthRaw в SBStatusBarDataManager.h, а затем отображать ее.

Вопрос. Как лучше всего читать или слушать эту переменную?

РЕДАКТИРОВАТЬ: Второстепенный вопрос: есть ли способ проанализировать код, уже скомпилированный в Obj-C?


person LibertasMens    schedule 27.07.2012    source источник
comment
Чтобы ответить на ваш другой вопрос, посмотрите на class_dump.   -  person Richard J. Ross III    schedule 28.07.2012
comment
Итак, вы хотите прослушать переменную, находящуюся вне вашего контроля (в системе, то есть в скомпилированном коде Apple), а не то, к какому исходному коду у вас есть доступ? Я сомневаюсь, что NSNotification поможет вам, если только не будет присутствует какое-то частное общесистемное уведомление о том, что ОС уже транслирует. Интересно, хорош ли КВО в этом случае? (Всего нуба КВО здесь)   -  person Nicolas Miari    schedule 28.07.2012
comment
Пока вы не упомянули подробности, это звучало так, как будто вы пытались взломать чужой двоичный файл;)   -  person Nicolas Miari    schedule 28.07.2012
comment
Наблюдение за ключом и значением — это то, что вам нужно, без взлома центра уведомлений.   -  person    schedule 28.07.2012
comment
@ranReloaded, он пытается прослушать изменения мощности сигнала Wi-Fi. Он знает, что такая информация заведомо доступна в строке состояния, раз она ее отображает. Таким образом, он пытается подключить слушателя к классу SpringBoard (двоичный код Apple), который имеет эти данные. Но ты прав. КВО тут тоже бесполезен.   -  person Nate    schedule 28.07.2012


Ответы (5)


Что вам действительно нужно, так это Наблюдение за ключом-значением< /а>. Не нужно возиться с NSNotificationcenter и т. д.

person Community    schedule 27.07.2012
comment
Найдите оболочку KVO, например mikeash.com/pyblog/, чтобы сделать его более доступным... - person Kendall Helmstetter Gelner; 28.07.2012
comment
@ H2CO3 Похоже, это то, что мне нужно, но я не уверен, как это реализовать. Если это класс SBStatusBarDataManager, и я хочу прочитать int gsmSignalStrengthRaw (который находится в структуре), как мне это сделать? Я читал страницу, это просто немного пугающе. - person LibertasMens; 28.07.2012
comment
Проблема с этим (также с уведомлениями, упомянутыми в других ответах) заключается в том, что вы можете наблюдать значение только в том случае, если класс позволяет вам - не все совместимо с KVO. @LibertasMens - person jscs; 28.07.2012
comment
@LibertasMens, у вас проблемы с получением объекта класса? Тогда используйте objc_getClass(). - person ; 28.07.2012
comment
Как говорит @JoshCaswell, не все совместимо с KVO. Если вы посмотрите на эти данные в SBStatusBarDataManager.h, вы увидите, что Apple только что закодировала его как простую вложенную структуру. Так что, хотя это приятно знать, это не решает его конкретную проблему. - person Nate; 28.07.2012
comment
@JoshCaswell Я могу использовать логотипы для подключения к классу. - person LibertasMens; 29.07.2012
comment
@Nate Если я использовал хук, о котором я упоминал, и получил доступ к классу, дает ли это мне доступ к данным в структуре? - person LibertasMens; 29.07.2012
comment
@LibertasMens, вам понадобится экземпляр этого класса (в частности, общий экземпляр, используемый в SpringBoard), но да ... это даст вам доступ. Смотрите ответ, который я опубликовал с кодом. - person Nate; 29.07.2012
comment
Снова минус. Пожалуйста, прекратите осуждать меня, кто бы это ни делал! - person ; 30.07.2012

Key Value Observing — отличная функция, но она не поможет вам (напрямую) решить эту конкретную проблему. Для тех, кто не знаком с классом, о котором он говорит, это закрытый класс в самом iOS SpringBoard. Таким образом, он не может контролировать то, как он публикует интересующие его данные.

Вы не можете наблюдать просто любые старые данные. Он должен быть закодирован, чтобы соответствовать принципу наблюдения за ключевыми значениями (KVO). Если вы посмотрите на SBStatusBarDataManager.h (это версия iOS 4... сгенерируйте нужную вам с помощью class-dump)... вы увидите, что она не закодирована таким образом :(

Но вы все равно можете использовать некоторые динамические функции времени выполнения Objective-C, чтобы получить данные. См. здесь о непосредственном доступе к закрытым/защищенным переменным экземпляра.

Затем просто локально объявите структуру, соответствующую тому, что находится в заголовке трамплина, и сделайте следующее:

// this was coded to match the iOS 5.0 header, but of course, this may
// change with each iOS version
typedef struct {
    char itemIsEnabled[23];
    char timeString[64];
    int gsmSignalStrengthRaw;
    int gsmSignalStrengthBars;
    char serviceString[100];
    char serviceCrossfadeString[100];
    char serviceImages[3][100];
    char operatorDirectory[1024];
    unsigned int serviceContentType;
    int wifiSignalStrengthRaw;
    int wifiSignalStrengthBars;
    unsigned int dataNetworkType;
    int batteryCapacity;
    unsigned int batteryState;
    char notChargingString[150];
    int bluetoothBatteryCapacity;
    int thermalColor;
    unsigned int thermalSunlightMode:1;
    unsigned int slowActivity:1;
    unsigned int syncActivity:1;
    char activityDisplayId[256];
    unsigned int bluetoothConnected:1;
    unsigned int displayRawGSMSignal:1;
    unsigned int displayRawWifiSignal:1;
} SbStatusBarDataType;

помощник для получения ivars по имени:

#import <objc/runtime.h>

- (void *) instanceVariableForObject: (id)obj andKey: (NSString *)key {
    if (key != nil) {
        Ivar ivar = object_getInstanceVariable(obj, [key UTF8String], NULL);
        if (ivar) {
            return (void *)((char *)obj + ivar_getOffset(ivar));
        }
    }
    return NULL;
}

и, наконец, получить данные следующим образом:

// get an instance to the data manager this way, or however you're 
//  doing it via Mobile Substrate
SBStatusBarDataManager* mgr = [SBStatusBarDataManager sharedDataManager];
SbStatusBarDataType data = *(SbStatusBarDataType*)[self instanceVariableForObject: mgr andKey: @"_data"];
int signalStrength = data.wifiSignalStrengthRaw;

Затем вы можете просто повторно запрашивать эти данные с некоторым интервалом, который вы считаете достаточно быстрым.

В противном случае попробуйте просмотреть методы в SBStatusBarDataManager.h. Похоже, что некоторые из них могут быть вызваны именно в то время, когда изменяется уровень сигнала. Если вы подключите эти методы, вы сможете отправить уведомление об изменении данных, чтобы вам не приходилось постоянно запрашивать данные.

Например:

- (void)_dataChanged;
- (void)_updateSignalStrengthItem;
- (void)_signalStrengthChange;

все выглядят как хорошие кандидаты на перехват, если вы пытаетесь определить, когда произошло изменение мощности сигнала WiFi. Но у меня нет опыта с ними, и это будет методом проб и ошибок с вашей стороны. Удачи!

Несколько ссылок, относящихся к вашему дополнительному вопросу:

дамп класса

Документация Apple по API среды выполнения Obj-C< /а>

person Nate    schedule 29.07.2012
comment
Чувак, я действительно запутался в этом вопросе. ха-ха Не уверен, почему я ожидал, что использование совершенно нового языка будет проще... Итак, используя код, предоставленный Джоном Калсбиком, является ли это универсальной функцией, которую я могу скопировать, или я помещаю в нее некоторые свои данные? Кажется, ему не нравится Ивар. 'Ivar' was not declared in this scope РЕДАКТИРОВАТЬ: Мои извинения, что я так беспомощен в этом. - person LibertasMens; 30.07.2012
comment
@LibertasMens, нет проблем, но да, теперь вы хорошо разбираетесь в сложных темах в Objective-C. Это то, что не особенно хорошо понятно, о чем свидетельствует тот факт, что, откровенно говоря, все остальные ответы просто неверны (или они не удосужились заметить, что класс, к данным которого вы хотите получить доступ, не находится под вашим контролем ). Я рекомендую использовать мою версию instanceVariableForObject:andKey: выше, а не оригинальную версию Джона Калсбека. Его версия полезна только для получения ivars (также известных как переменные-члены) внутри self (также известных как this в других языках). - person Nate; 30.07.2012
comment
Другое преимущество использования моего кода, приведенного выше, заключается в том, что я указываю, что вы должны #import <objc/runtime.h>. Вероятно, поэтому ваш компилятор не находит тип Ivar. - person Nate; 30.07.2012
comment
У меня возникают две проблемы с объявлениями, одна из которых 'SBStatusBarDataManager' does not name a type, а другая 'self' was not declared in this scope. Вот мой текущий код, не могли бы вы взглянуть? Я, наверное, просто что-то неправильно понял. - person LibertasMens; 30.07.2012
comment
@LibertasMens, вы знакомы с языком C? Вам нужно #include заголовки, чтобы типы внутри них были видны. В Objective-C у вас также есть #import, аналогичная конструкция. В любом случае вам потребуется #import "SBStatusBarDataManager.h", чтобы компилятор мог узнать о SBStatusBarDataManager. Вы также не последовали моему совету по поводу использования моей версии instanceVariableForObject:andKey:. Насколько вы новичок в Objective-C? Возможно, стоит сначала создать несколько программ hello world. Вы пытаетесь сразу перейти к очень продвинутому взлому... - person Nate; 30.07.2012
comment
Извините, похоже, в вашем коде есть обе версии метода instanceVariable*. В любом случае у вас есть сиротский код, который, по-видимому, существует за рамками любого класса или метода. Это вызовет у вас проблемы со ссылкой self. Опять же, похоже, что вам нужно сначала создать несколько простых программ с помощью Objective-C. - person Nate; 30.07.2012
comment
Ах, не могу поверить, что я пропустил это. На самом деле я поместил `#import SBStatusBarDataManager.h в код после, я поместил его в pastebin. Извините за путаницу. Видимо установили не тот SDK и не смогли найти файл, поэтому я его не импортировал. Глупая ошибка с моей стороны. - person LibertasMens; 30.07.2012

Используйте NSNotificationCenter для отправки значений в/из разных классов. Вот хороший пример использования NSNotifications Send и получать сообщения через NSNotificationCenter в Objective-C?

person Glavid    schedule 27.07.2012
comment
Не применимо напрямую к этой проблеме (но хорошая общая информация). Он пытается отслеживать изменения данных в классе iOS (SpringBoard), который он не контролирует. - person Nate; 28.07.2012

Ознакомьтесь с NSNotificationCenter. Это позволит вам добавлять слушателей к переменным, когда переменная изменяет свою публикацию в центре уведомлений. Затем вы можете «услышать» эти изменения в любом классе.

Описание NotificationCenter в документе Apple:

Объект NSNotificationCenter (или просто центр уведомлений) предоставляет механизм для широковещательной передачи информации внутри программы. Объект NSNotificationCenter по сути является таблицей отправки уведомлений.

Быстрый пример:

Добавить слушателя

 [[NSNotificationCenter defaultCenter] addObserver:self 
                                          selector:@selector(showMainMenu:) 
                                              name:@"loginComplete" object:nil];

Опубликовать уведомление для входа в системуComplete

[[NSNotificationCenter defaultCenter] postNotificationName:@"loginComplete" object:nil];

Прослушайте уведомление.

- (void)showMainMenu:(NSNotification *)note {
     NSLog(@"Received Notification - Someone seems to have logged in"); 
 }
person random    schedule 27.07.2012
comment
Не применимо напрямую к этой проблеме (но хорошая общая информация). Он пытается отслеживать изменения данных в классе iOS (SpringBoard), который он не контролирует. - person Nate; 28.07.2012

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

Вот руководство для начала: Шаблоны в Objective-C: шаблон наблюдателя

А также взгляните на этот вопрос на SO: Какой лучший способ сделать наблюдателя/наблюдаемого в target-c (версия для iPhone)

person Vincent Mimoun-Prat    schedule 27.07.2012
comment
Не применимо напрямую к этой проблеме (но хорошая общая информация). Он пытается отслеживать изменения данных в классе iOS (SpringBoard), которым он не управляет и который не был закодирован для совместимости с KVO. - person Nate; 28.07.2012