若一个类有实例变量 NSString *_foo ,调用setValue:forKey:时,可以以foo还是 _foo 作为key?

KVC在Objective-C中用于访问和修改对象属性,即使没有公开的setter方法。当setValue:forKey:被调用时,它会按顺序尝试通过setter、成员变量、下划线开头的变量以及驼峰命名的变量进行赋值。如果不存在匹配的key,会执行valueForUndefinedKey:方法,默认抛出异常。测试显示,KVC优先尝试成员变量,并遵循特定的查找顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<ViewController 0x7fead440c430> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key _foo.'


答案:都可以

为什么?

无论是Swift还是Objective-C,KVC的定义都是对NSObject的扩展来实现的(Objective-c中有个显式的NSKeyValueCoding类别名,而Swift没有这个类别,也不需要)所以对于所有继承了NSObject在类型,都能使用KVC(一些纯Swift类和结构体是不支持KVC的),下面是KVC最为重要的四个方法:

- (nullable id)valueForKey:(NSString *)key;                          //直接通过Key来取值
- (void)setValue:(nullable id)value forKey:(NSString *)key;          //通过Key来设值
- (nullable id)valueForKeyPath:(NSString *)keyPath;                  //通过KeyPath来取值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  //通过KeyPath来设值

其他的一些方法:

+ (BOOL)accessInstanceVariablesDirectly;
//默认返回YES,表示如果没有找到Set方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜索
- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
//KVC提供属性值确认的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
//这是集合操作的API,里面还有一系列这样的API,
### 如何在 Flutter 中调用 Objective-C 初始化方法 `initWithAppkey:channel:` 为了实现在 Flutter 中调用带有特定初始化方法的 Objective-C 代码,可以遵循以下方式构建平台通道并定义相应的逻辑。 #### 定义 Objective-C 插件工厂接口 首先,在 iOS 原生端创建一个继承自 `NSObject<FlutterPlatformViewFactory>` 的来负责视图组件的创建工作。对于具有特殊初始化需求的情况,则需重载其构造函数以便传递必要的参数给原生控件[^1]: ```objectivec #import <Foundation/Foundation.h> #import <Flutter/Flutter.h> NS_ASSUME_NONNULL_BEGIN @interface CustomPluginViewFactory : NSObject<FlutterPlatformViewFactory> /// 自定义构造方法以接受额外参数 -(instancetype)initWithAppKey:(NSString *)appKey channel:(NSObject<FlutterBinaryMessenger>*)messenger; @end NS_ASSUME_NONNULL_END ``` 接着实现上述声明的方法体,并确保能够正确解析来自 Dart 层面传入的数据作为 app key 参数的一部分。 #### 创建 MethodChannel 进行通信 为了让 Dart 和 Native 双方都能识别同一个 Channel 名称,通常会约定好固定的字符串常量用于标识此渠道。当接收到消息,`handleMethodCall` 函数会被触发执行相应业务逻辑处理[^3]。 ```objectivec @implementation CustomPluginViewFactory { NSString *_appKey; } -(instancetype)initWithAppKey:(NSString *)appKey channel:(NSObject<FlutterBinaryMessenger>*)messenger{ self = [super init]; if (self) { _appKey = appKey; // 使用相同的 name 创建 MethodChannel 实现双向通讯机制 FlutterMethodChannel *methodChannel = [FlutterMethodChannel methodChannelWithName:@"com.example.custom_plugin" binaryMessenger:messenger]; // 设置 message handler 处理来自 flutter 方法请求 __weak typeof(self) weakSelf = self; [methodChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result){ if ([call.method isEqualToString:@"getPlatformVersion"]) { result(@"iOS " stringByAppendingString:[UIDevice currentDevice].systemVersion); } else { result(FlutterMethodNotImplemented); } }]; } return self; } ``` #### 在 Dart 端建立连接 最后回到 Flutter 应用程序内部编写对应的 Dart 文件引入所需包并配置 MessageChannel 或者 MethodChannel 来发起跨平台交互命令[^2][^4]: ```dart import 'package:flutter/services.dart'; class CustomPlugin { static const platform = MethodChannel('com.example.custom_plugin'); Future<String?> getPlatformVersion() async { try { final String version = await platform.invokeMethod('getPlatformVersion'); return version; } on PlatformException catch (e) { return "Failed to invoke native code: '${e.message}'."; } } void setupCustomPlugin(String appKey) { BasicMessageChannel<String> basicMessageChannel = BasicMessageChannel<String>('com.example.custom_plugin', StringCodec()); Map<String, dynamic> args = {'appKey': appKey}; platform.invokeMethod('initializeWithAppKeyAndChannel', args); } } ``` 通过这种方式就可以成功地从 Flutter 调用了带有所需初始化参数的 Objective-C 构造器了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值