在子类接口中,我声明了一个由超类实现的方法,因为返回了一个不同的对象类型,因为子类是专用的。但是,我没有必要在子类中实际实现该方法 - 超类的实现工作正常。不幸的是,这个模式现在似乎在最新版本的Xcode上给了我Method definition for … not found error
。
我知道我可以在diagnostic push
周围pop
和@implementation
@interface GeneralItem : NSObject
@end
@interface GeneralGroup : NSObject
- (GeneralItem *)item;
@end
@interface ItemA : GeneralItem
@end
@interface GroupA : GeneralGroup
- (ItemA *)item;
@end
关闭所有此类警告,但我和#39;而不是采取这种极端方法,因为警告在其他情况下很有用。 (如果这可以标记个别方法的沉默,我全都耳朵)
以下是出现此问题的几个示例实现之一:
#import "Test.h"
@implementation GeneralGroup
- (GeneralItem *)item
{
return nil;
}
@end
@implementation GroupA
// Warning: Method definition for 'item' not found
@end
super
要清楚,一切都编译并正常工作,根据我的理解,编译器应该知道超类实现了这个方法,更不用说Objective-C对于方法定义中的类型重载并不太挑剔。
我想避免实现该方法并简单地调用super
,因为我将其视为完全冗余的代码,但是如果有人可以向我确认编译器将优化掉直接调用{ {1}}所以运行时可以做其通常的事情,而不需要对子类进行进站,这是使这个警告静音的唯一方法,那就这样吧。
以下是其他几种情况。
第一种情况是公共基类(或抽象超类)实现某些事物的共享实现,比如块,但我们只希望某些子类有选择地声明它们对它的支持,并且类型正确注释:< / p>
@interface GeneralItem : NSObject
@end
@interface GeneralGroup : NSObject
@end
@interface ItemA : GeneralItem
@end
@interface GroupA : GeneralGroup
- (void)loadItemWithCompletionHandler:(void (^)(ItemA *item))completionHandler;
@end
@interface ItemB : GeneralItem
@end
@interface GroupB : GeneralGroup
- (void)loadItemWithCompletionHandler:(void (^)(ItemB *item))completionHandler;
@end
#import "BlockTest.h"
@interface GeneralGroup ()
- (id)item;
- (void)loadItemWithCompletionHandler:(void (^)(Item *item))completionHandler;
@end
@implementation GeneralGroup
- (void)loadItemWithCompletionHandler:(void (^)(Item *item))completionHandler;
{
if (completionHandler) completionHandler(self.item);
}
@end
@implementation GroupA
// Warning: Method definition for 'loadItemWithCompletionHandler:' not found
// A custom implementation of -item can be here, for instance
@end
我应该注意,如果您在- (void)loadItemWithCompletionHandler:(void (^)(Item *item))completionHandler;
的公开标题中将方法声明为GroupA
,则不会收到警告,但您执行获取&#34;方法没有找到定义&#34;将类型更改为最初指定类型的子类时发出警告。
第二个是您只想为超类提供的方法提供更多上下文(在此处使用NSObject
&#39; copy
,但这适用于任何类型为{{1的方法我们希望用更准确的类型重新声明,所以像属性链这样的东西可以毫不费力地工作):
id
@interface Subclass : NSObject
- (instancetype)copy;
@end
答案 0 :(得分:2)
这似乎是一个机会以某种方式表明-[GeneralGroup item]
可能返回一个GeneralItem的子类的实例。
最快的方法是在__kindof
上使用-[GeneralGroup item]
注释,表明返回值是GeneralItem或任何子类:
@interface GeneralGroup : NSObject
- (__kindof GeneralItem *)item;
@end
@interface GroupA : GeneralGroup
@end
由于您不再在GroupA上重新声明-item
,因此您无法在其实施中收到警告 - 但如果您愿意,您仍然可以自由覆盖-item
,并返回ItemA的实例。
如果您想要更具体一点,可以考虑使用lightweight generics:
@interface GeneralGroup<__covariant ItemType: GeneralItem*> : NSObject
- (ItemType)item;
@end
这对于编译器来说是相同的,但是向读取头部的其他开发人员表达了更多信息:他们知道-item
返回一个GeneralItem或子类,并且 - 因为存在__covariant
属性 - GeneralGroup的子类可能需要比GeneralItem更具体的关联项类型。
然后,呼叫者可以自由地将-[GroupA item]
的返回值键入为ItemA:
GroupA *ga = [[GroupA alloc] init];
ItemA *ia = ga.item; // no warning
通过进一步重构,您可能会发现每个项目都不需要特定的组类型;相反,通常一般的分组实现可以满足多个项类型,并且在组的本地实例上声明了特定的项类型。 (这是怎样集合的NSArray一样工作:他们声明泛型包含的对象类型,以及特定的阵列实例注释为在点包含一个特定的对象,他们&#39;重新创建或周围通过。)
答案 1 :(得分:0)
您可以暂时将警告静音:
在导致警告的行之前:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wthe-error-to-ignore"
在线之后:
// this resets clang's diagnostic system to the state it was in before we called "push"
#pragma clang diagnostic pop