Key Value Observing is a great feature, but it doesn't help you (directly) with this particular problem. For those not familiar with the class he's referring to, it's a private class within the iOS SpringBoard itself. So, he doesn't have control over how it publishes the data he's interested in.
You can't observe just any old data. It has to be coded to be Key Value Observing (KVO) compliant. If you look at the SBStatusBarDataManager.h (this is the iOS 4 version ... generate the one you need with class-dump
) ... you'll see that it's not coded that way :(
But, you could use some dynamic Objective-C runtime feature to get at the data anyway. See here on getting at private/protected instance variables directly.
Then, just locally declare a struct to match what's in the springboard header, and do this:
// 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;
a helper to retrieve ivars by name:
#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;
}
and finally, get the data like so:
// 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;
You could then just repeatedly query this data, at some interval that you consider fast enough.
Otherwise, try looking at the methods in SBStatusBarDataManager.h. It looks like some of them might conceivably be called at the precise time that signal strength changes. If you hook those methods, you might be able to push a notification that the data has changed, so that you don't have to constantly poll for the data.
For example:
- (void)_dataChanged;
- (void)_updateSignalStrengthItem;
- (void)_signalStrengthChange;
all look like good candidates for hooking, if you're trying to determine when there's been a change to WiFi signal strength. But, I have no experience with those, and it'll be trial-and-error on your part. Good luck!
A couple references pertaining to your Secondary question:
class-dump
Apple docs on Obj-C runtime APIs