我遇到了一个有趣的问题,但却无法找到任何相关文档... properties
中声明的protocol
有时未在特定类中实现到那个protocol
并发生运行时异常。在某些奇怪的情况下,dynamic property
定义是否被优化了?可以protocols
与properties
一起使用dynamic
吗?protocol
任何有关这方面的见解将不胜感激。
以下是一些更多细节。
给出@protocol MyProtocol <NSObject>
@property (nonatomic, strong) id someProperty;
@end
:
protocol
和实现@interface MyClass <MyProtocol>
@end
@implementation MyClass
@dynamic someProperty;
@end
的类如此:
class_getProperty(myClass, propertyName);
我注意到有时我无法通过调用
获取任何信息properties
代表protocol
中的@protocol MyProtocol <NSObject>
@property (nonatomic, strong) id someData;
@end
@interface MyObject : NSObject <MyProtocol>
@end
@implementation MyObject
@dynamic someData;
@end
。这只发生在一些类中,似乎是零星的。
我正在运行最新的Xcode 4并链接到iOS 6 SDK。我确实在同一台机器上安装了预发布的Xcode 5,虽然它不是默认的(通过xcode-select)。
如果您运行此代码:
const char *name = [@"someData" UTF8String];
objc_property_t property = class_getProperty([MyObject class], name);
const char *attributes = property_getAttributes(property);
然后你运行
property
即使property
不存在,您也会获得property
的元数据。换句话说,您不需要合成属性来获取它的属性。运行时仍然知道它。亲自试试吧。问题是有时这种情况不会发生。我想知道导致运行时不知道property
属性的条件。
我的临时解决方法是复制protocol
中的所有@interface MyClass <MyProtocol>
@property (nonatomic, strong) id someProperty;
@end
@implementation MyClass
@dynamic someProperty;
@end
定义并将其粘贴到.h文件中:
{{1}}
这很好,虽然远非理想。但是,它表明我的代码工作正常,问题出在其他地方。
如果需要,我很乐意提供更多详细信息或背景信息。
答案 0 :(得分:2)
协议定义方法,可选方法和所需方法。
属性是抽象方法,如果协议将属性定义为必需,则必须实现所需的方法:通常使用@synthesize
...但可以通过其他方式完成
(假设非脆弱的ABI / Modern Runtime)为了简单起见使用readonly
@property(readonly)int dog;
可能会受到启发:
@synthesize dog;
或
@synthesize dog = _dog; // synthesize standard getter for the iVar _dog
或
- (int) dog
{
return _dog; // or dog, or cat/5 or 5 or whatever
}
编辑:重新动态属性
@dynamic
是一个关键字,它不会生成满足属性要求的方法,它所做的是通知编译器它以某种其他方式“处理”...
这种动态调度可以在运行时通过几种不同的方法来完成,一种是在运行时添加方法实现,另一种是通过将运行时用于未解析的选择器。 (我有一个关于使用动态属性在字典中使用通用KV存储的类似问题)
请参阅:Using NSMutableDictionary as backing store for properties
答案 1 :(得分:1)
似乎有一种混乱:
声明属性足以使属性在运行时存在。没有必要实施。这就是Objective-c的工作原理。方法不必在编译时存在,您可以动态添加它们(例如Core Data所做的)。
@dynamic
在运行时没有任何作用。在编译时,它是一个占位符,表示“不要给我编译器警告,这里没有定义getter / setter”。在最新的LLVM上,它还说“不要自动合成”。
我的建议:
如果要通过类别添加协议,请确保已加载类别。这似乎是运行时反射最常见的问题。
要进行调试,也请尝试使用class_conformsToProtocol
。如果有一个符合协议的类而没有它具有协议声明的属性,那将是很奇怪的。
答案 2 :(得分:0)
经过大量调试和测试后,我得出结论,这是一个错误。如果有人有任何相反的证据或建议随时发布。错误是这样的:
有时 在property
中定义protocol
,然后某个类符合所述protocol
时,如果property's
被标记为property
,则运行时不会意识到dynamic
属性(例如,class_getProperty失败)。
Rememeber,dynamic
提供 no implementation ,它只是抑制警告,但是,property
属性仍应通过运行时检索。
我想添加一些有用的代码片段来解决/调试这些类型的问题:
- (NSArray *)propertyNamesForClass:(Class)aClass includeInherited:(BOOL)shouldIncludeInherited;
{
NSMutableArray *names = [NSMutableArray array];
uint propertyCount = 0;
objc_property_t *properties = class_copyPropertyList(aClass, &propertyCount);
for (uint i = 0; i < propertyCount; i++) {
[names addObject:[NSString stringWithUTF8String:property_getName(properties[i])]];
}
if (shouldIncludeInherited) {
Class superClass = aClass;
while ((superClass = class_getSuperclass(superClass))) {
uint superPropertyCount = 0;
objc_property_t *superProperties = class_copyPropertyList(superClass, &superPropertyCount);
for (uint i = 0; i < superPropertyCount; i++) {
[names addObject:[NSString stringWithUTF8String:property_getName(superProperties[i])]];
}
}
}
NSArray *sortedNames = [names sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
return sortedNames;
}
- (NSArray *)protocolNamesForClass:(Class)aClass includeInherited:(BOOL)shouldIncludeInherited;
{
NSMutableArray *names = [NSMutableArray array];
uint protocolCount = 0;
__unsafe_unretained Protocol **protocolArray = class_copyProtocolList(aClass, &protocolCount);
for (uint i = 0; i < protocolCount; i++) {
[names addObject:NSStringFromProtocol(protocolArray[i])];
}
if (shouldIncludeInherited) {
Class superClass = aClass;
while ((superClass = class_getSuperclass(superClass))) {
uint superProtocolCount = 0;
__unsafe_unretained Protocol **superProtocolArray = class_copyProtocolList(superClass, &superProtocolCount);
for (uint j = 0; j < superProtocolCount; j++) {
[names addObject:NSStringFromProtocol(superProtocolArray[j])];
}
}
}
NSArray *sortedNames = [names sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
return sortedNames;
}
- (NSArray *)propertyNamesForProtocol:(Protocol *)aProtocol
{
NSMutableArray *names = [NSMutableArray array];
uint protocolPropertyCount = 0;
objc_property_t *properties = protocol_copyPropertyList(aProtocol, &protocolPropertyCount);
for (uint j = 0; j < protocolPropertyCount; j++) {
[names addObject:[NSString stringWithUTF8String:property_getName(properties[j])]];
}
NSArray *sortedNames = [names sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
return sortedNames;
}