在 Swift 3 的值类型中访问 Objective-C 类别的属性(关联参考)
Posted
技术标签:
【中文标题】在 Swift 3 的值类型中访问 Objective-C 类别的属性(关联参考)【英文标题】:Access Objective-C Category's Property (Associated Reference) in Swift 3's Value Type 【发布时间】:2016-10-12 11:29:28 【问题描述】:在我的 Objective-C 类的 .h 文件中,我为 NSIndexPath 创建了一个类别,如下所示:
@interface NSIndexPath (YVTableView)
@property (nonatomic, assign) NSInteger subRow;
@end
在那个类的 .m 文件中,我已经实现了这样的功能:
static void *SubRowObjectKey;
@implementation NSIndexPath (YVTableView)
@dynamic subRow;
- (NSInteger)subRow
id subRowObj = objc_getAssociatedObject(self, SubRowObjectKey);
return [subRowObj integerValue];
- (void)setSubRow:(NSInteger)subRow
id subRowObj = [NSNumber numberWithInteger:subRow];
objc_setAssociatedObject(self, SubRowObjectKey, subRowObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
@end
现在,当我在 Swift 3 中使用 IndexPath 访问 NSIndexPath 的 subRow 属性时,它给了我错误:
“IndexPath”类型的值没有成员“subRow”
如果我尝试使用类型转换来访问它
let subIndexPath = indexPath as NSIndexPath
let subRowIndex = subIndexPath.subRow
它总是将“0”作为“subRow”值返回给我。可能是因为 IndexPath 是值类型而 NSIndexPath 是引用类型。
我已经使用 Objective-C 将 UITableViewDelegate 实现到我的自定义委托并将其实现到 Swift 类,但是在我实现自定义委托方法的 Swift 中,我遇到了这个问题。
我还尝试在我的自定义委托实现(Swift 代码)中使用 NSIndexPath 而不是 IndexPath,但它给了我错误“YVViewController 类型不符合协议,候选者的类型不匹配”。
这是我的自定义委托声明:
@protocol YVTableViewDelegate <UITableViewDelegate>
@required
- (UITableViewCell *)tableView:(SKSTableView *)tableView cellForSubRowAtIndexPath:(NSIndexPath *)indexPath;
@end
它在 Swift 2.x 上运行得非常好,但是在迁移到 Swift 3 之后,我遇到了这个问题。
【问题讨论】:
也许你只是忘了给subRow
设置一个非0的值?我刚试过你的代码,对我来说没问题。
不,它在 Objective-C -> UITableViewDelegate 的子类中具有价值,然后使用自定义委托我将它传递给 Swift 类,但在 Swift -> 自定义委托实现中。我正面临这个问题。
【参考方案1】:
与NSIndexPath
关联的subRow
不会与从NSIndexPath
转换的IndexPath
关联,因为它们不是同一个“对象”。 IndexPath
是 Swift 中的值类型,用 struct
关键字定义,所以它不能有 Objective-C 关联的对象。
因此,即使您在 Objective-C 代码中将 NSIndexPath
的值设置为 subRow
,当将 NSIndexPath
强制转换为 Swift 的 IndexPath
时,该值也会丢失。这就是为什么当您再次将 IndexPath
转换回 NSIndexPath
时,subRow
的值始终为 0,这是默认值。
在您的情况下,您需要在 Swift 中声明协议并将索引路径参数类型指定为NSIndexPath
。
func tableView(_ tableView: SKSTableView, cellForSubRowAt indexPath: NSIndexPath) -> UITableViewCell
【讨论】:
我的问题有什么解决方案?如何在 Swift 3 中使用该 Objective-C 代码? 我刚刚更新了答案@Yash。在您的 Swift 自定义委托实现中,将参数类型声明为NSIndexPath
而不是 IndexPath
。
我已经尝试在我的自定义委托实现(Swift 代码)中使用 NSIndexPath 而不是 IndexPath,但它给了我错误“YVViewController 类型不符合协议,候选人有非匹配类型”。
您还必须更改协议声明中的类型。
添加了我的自定义代表声明也有问题。【参考方案2】:
但是,您可以按如下方式更新您的类别:-
- (NSInteger)subRow
id myclass = [SKSTableView class];
// id subRowObj = objc_getAssociatedObject(self, SubRowObjectKey);
id subRowObj = objc_getAssociatedObject(myclass, SubRowObjectKey);
return [subRowObj integerValue];
- (void)setSubRow:(NSInteger)subRow
id subRowObj = [NSNumber numberWithInteger:subRow];
id myclass = [SKSTableView class];
// objc_setAssociatedObject(self, SubRowObjectKey, subRowObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_setAssociatedObject(myclass, SubRowObjectKey, subRowObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
【讨论】:
以上是关于在 Swift 3 的值类型中访问 Objective-C 类别的属性(关联参考)的主要内容,如果未能解决你的问题,请参考以下文章
无法访问 [AnyHashable:Any] 类型的值 - Swift 4
无法在 Swift 3 中调用非函数类型“UICollectionView”的值
Swift 3:如何在48字节的CFData中访问matrix_float3x3的值?