Несоответствующие имена -init методов - PullRequest
4 голосов
/ 31 октября 2010

Я обнаружил странный сценарий, который выдает предупреждение компилятора в XCode, которое я не считаю действительным предупреждением.

В качестве примера я создал два класса, ClassA и ClassB, у каждого из которых есть метод init с именем -initWithSomething: Один принимает (NSDate *) как «что-то», а другой принимает (NSString *)

Класс A

// ClassA.h
#import <Foundation/Foundation.h>

@interface ClassA : NSObject {
}
-(id)initWithSomething:(NSDate *)something;
@end

// ClassA.m
#import "ClassA.h"

@implementation ClassA
-(id)initWithSomething:(NSDate *)something {
    if (self = [super init]) {
    }
    return self;
}
@end

Класс B

// ClassB.h
#import <Foundation/Foundation.h>

@interface ClassB : NSObject {
}
-(id)initWithSomething:(NSString *)something;
@end

// ClassB.m
#import "ClassB.h"

@implementation ClassB
-(id)initWithSomething:(NSString *)something {
    if (self = [super init]) {
    }
    return self;
}
@end

Реализация другого класса, который использует как ClassA, так и ClassB

#import "ExampleClass.h"
#import "ClassA.h"
#import "ClassB.h"

@implementation ExampleClass

-(void)doSomething {
    NSDate *date = [NSDate date];
    NSString *string = [NSString stringWithFormat:@"Test"];

    ClassA *classA = [[ClassA alloc] initWithSomething:date];
    ClassB *classB = [[ClassB alloc] initWithSomething:string]; // Produces "Incompatible pointer types sending 'NSString *' to parameter of type 'NSDate *'
    ClassB *classB2 = [[ClassB alloc] initWithSomething:[NSString stringWithFormat:@"Test"]]; // Does NOT produce a warning
    ClassB *classB3 = [[ClassB alloc] initWithSomething:@"Test"]; // Produces the same warning as above.

    [classA release];
    [classB release];
    [classB2 release];
    [classB3 release];
}

Это ошибка компилятора? Похоже, что ни одна из этих строк не должна выдавать предупреждение, тем более что строка, в которой запускается «classB2», не выдает предупреждений.
На самом деле этот код работает нормально, вызывается правильный класс '-initWithSomething: и передается соответствующий тип аргумента.

Ясно, что более явные имена методов позволят избежать этой проблемы, но я хотел бы знать, почему компилятор не может справиться с этим.

Примечание : Я должен добавить, что это, кажется, происходит только с методами -init, любые другие функции экземпляра или класса, похоже, не выдают предупреждение.

Ответы [ 3 ]

3 голосов
/ 31 октября 2010

Я думаю, что проблема в том, что +alloc возвращает общий id.

Это означает, что к нему может быть вызван любой метод, и компилятор увидит, что первый импортированный метод, имеющий подпись -initWithSomething, предназначен для класса A, который ожидает объект типа NSDate *,

Кроме того, я считаю, что метод +stringWithFormat возвращает id, который может быть совместим с NSDate.

РЕДАКТИРОВАТЬ:

Простое решение этой проблемы:

@interface ClassA

+(ClassA *) typeSafeAlloc;

// ...
@end

@implementation ClassA

+(ClassA *) typeSafeAlloc
{
    // self is the class variable,  which is the same as:
    // return [ClassA alloc];
    return [self alloc];
}
@end

И повторите процесс с ClassB (с typeSafeAlloc, возвращающим ClassB объект)

2 голосов
/ 31 октября 2010

alloc возвращает объект типа id, и поэтому компилятор предполагает, что initWithSomething принадлежит Class A (первый интерфейс класса, с которым он сталкивается, имеет имя метода).

Что-то вроде [(ClassB*)[ClassB alloc] initWithSomething:string]; должен решить проблему.

1 голос
/ 31 октября 2010

Посмотрите на тип возвращаемого значения +stringWithFormat

Возвращает строку, созданную с использованием заданной строки формата в качестве шаблона, в которую подставляются оставшиеся значения аргумента.

+ (id)stringWithFormat:(NSString *)format, ...

(из http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html)

Компилятор знает, что строка является NSString*, то же самое с @"literals". Однако id может быть чем угодно (дажеNSSDate*).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...