1

正如我所说,Objective-C 是全新的。不过,我有几年的编程经验,而且我学得很快。

一般问题:我想监听不同文件中的变量,然后执行特定操作以响应对该变量的更改。

具体问题:我想修改 iPhone 显示 WiFi 信号的方式。目前它有4个状态,但我想让它有8个状态。我希望以某种方式收听(或定期读取)变量wifiSignalStrengthRawSBStatusBarDataManager.h然后显示它。

问题:阅读或聆听该变量的最佳方法是什么?

编辑:次要问题:有没有办法分析已经在 Obj-C 中编译的代码?

4

5 回答 5

3

你真正想要的是Key-Value Observing。无需修改 NSNotificationcenter 等...

于 2012-07-27T21:12:48.123 回答
2

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 信号强度何时发生变化,那么所有这些看起来都适合挂接。但是,我对这些没有经验,这将是您的反复试验。祝你好运!

与您的次要问题有关的一些参考资料:

类转储

关于 Obj-C 运行时 API 的 Apple 文档

于 2012-07-29T01:07:26.393 回答
1

使用 NSNotificationCenter 向/从不同的类发送值。这是一个在 Objective-C 中使用 NSNotifications 通过 NSNotificationCenter 发送和接收消息的好例子 ?

于 2012-07-27T20:55:02.930 回答
1

查看NSNotificationCenter。当变量更改发布到通知中心时,这将允许您向变量添加侦听器。然后,您可以在任何课程中“听到”这些变化。

NotificationCenter 的 Apple 文档描述:

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"); 
 }
于 2012-07-27T20:57:52.247 回答
0

如果您是对要侦听的变量进行更改的人,则应使用观察者模式。

这是一个帮助您入门的教程:Objective-C 中的模式:观察者模式

还可以看看关于 SO 的问题:What's the best way to doobserver/observable in objective-c (iphone version)

于 2012-07-27T20:53:09.950 回答