Слушате променлива в различен файл?

Както казах, съвсем нов за Objective-C. Все пак имам няколко години опит в програмирането и се уча бързо.

Общ проблем: Искам да прослушам променлива в друг файл, след което да извърша определено действие в отговор на промените в тази променлива.

Конкретен проблем: Искам да променя начина, по който iPhone показва WiFi сигнал. Понастоящем има 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 ще ви помогне, освен ако няма има частно известие за цялата система, че операционната система вече излъчва. Чудя се дали KVO е добър в този случай? (Общо KVO noob тук)   -  person Nicolas Miari    schedule 28.07.2012
comment
Докато не споменахте подробностите, звучеше сякаш се опитвате да разбиете двоичния файл на някой друг ;)   -  person Nicolas Miari    schedule 28.07.2012
comment
наблюдението на ключ-стойност е това, което искате, без хакване на центъра за уведомяване.   -  person    schedule 28.07.2012
comment
@ranReloaded, той се опитва да чуе промени в силата на WiFi сигнала. Той знае, че такава информация очевидно е налична в лентата на състоянието, тъй като тя я показва. По този начин той се опитва да закачи слушател към класа SpringBoard (двоичния файл на Apple), който има тези данни. Прав си обаче. KVO също е безполезен тук.   -  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 Ако използвам куката, която споменах, и получа достъп до class, това дава ли ми достъп до данни в struct? - person LibertasMens; 29.07.2012
comment
@LibertasMens, ще ви трябва екземпляр от този клас (по-специално споделеният екземпляр, използван в SpringBoard), но да ... това ще ви даде достъп. Вижте отговора, който публикувах с код. - person Nate; 29.07.2012
comment
Отново глас против. Моля, спрете серийното гласуване против мен, който и да го направи! - person ; 30.07.2012

Наблюдението на ключовите стойности е страхотна функция, но не ви помага (директно) с този конкретен проблем. За тези, които не са запознати с класа, който той има предвид, това е частен клас в самия iOS SpringBoard. Така че той няма контрол върху това как публикува данните, от които се интересува.

Не можете да наблюдавате само стари данни. Той трябва да бъде кодиран, за да бъде съвместим с Key Value Observing (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 сигнала. Но аз нямам опит с тях и това ще бъде метод проба-грешка от ваша страна. Късмет!

Няколко препратки, отнасящи се до вашия Вторичен въпрос:

class-dump

Документи на 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: по-горе, вместо оригиналната версия от John Calsbeek. Неговата версия е полезна само за получаване на ivars (известни още като членски променливи) в рамките на self (известни още като това на други езици). - 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 Изпращане и да получавате съобщения чрез NSNotificationCenter в Objective-C?

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

Вижте NSNotificationCenter. Това ще ви позволи да добавяте слушатели към променливи, когато променливата се промени, тя се публикува в центъра за уведомяване. След това можете да "чуете" тези промени във всеки клас.

Описание на Apple doc на NotificationCenter:

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

Бърз пример:

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

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

Публикувайте известие за loginComplete

[[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: Кой е най-хубавият начин да направите наблюдател/наблюдаем в objective-c (iphone версия)

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