抑制"%@未找到的方法定义"

时间:2018-05-15 16:43:29

标签: objective-c compiler-warnings xcode9 suppress-warnings

在子类接口中,我声明了一个由超类实现的方法,因为返回了一个不同的对象类型,因为子类是专用的。但是,我没有必要在子类中实际实现该方法 - 超类的实现工作正常。不幸的是,这个模式现在似乎在最新版本的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;而不是采取这种极端方法,因为警告在其他情况下很有用。 (如果这可以标记个别方法的沉默,我全都耳朵)

以下是出现此问题的几个示例实现之一:

Test.h

#import "Test.h"

@implementation GeneralGroup

- (GeneralItem *)item
{
    return nil;
}

@end

@implementation GroupA
// Warning: Method definition for 'item' not found

@end

Test.m

super

要清楚,一切都编译并正常工作,根据我的理解,编译器应该知道超类实现了这个方法,更不用说Objective-C对于方法定义中的类型重载并不太挑剔。

我想避免实现该方法并简单地调用super,因为我将其视为完全冗余的代码,但是如果有人可以向我确认编译器将优化掉直接调用{ {1}}所以运行时可以做其通常的事情,而不需要对子类进行进站,这是使这个警告静音的唯一方法,那就这样吧。

编辑1

以下是其他几种情况。

第一种情况是公共基类(或抽象超类)实现某些事物的共享实现,比如块,但我们只希望某些子类有选择地声明它们对它的支持,并且类型正确注释:< / p>

BlockTest.h

@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

BlockTest.m

#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的方法我们希望用更准确的类型重新声明,所以像属性链这样的东西可以毫不费力地工作):

Subclass.h

id

Subclass.m

@interface Subclass : NSObject

- (instancetype)copy;

@end

2 个答案:

答案 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