Использование необъявленной ошибки идентификатора в моем случае

Мой код вызывает функцию библиотеки C:

@implementation Store
  ...
  -(void) doWork {
    // this is a C function from a library
    int data = getData(); 
    ...
  }
end

Я тестирую вышеупомянутую функцию, хочу издеваться над функцией C getData() в моем тесте вот мой тестовый пример:

@interface StoreTests : XCTestCase {
    int mData;
    Store *store;
}
@end

@implementation StoreTests

-(void) setUp {
  [super setUp];
   mData = 0;
   store = [[Store alloc] init];
}

-(void) testDoWork {
  // this call will use the mocked getData(), no problem here.
  [store doWork];
}

// mocked getData()
int getData() {
   mData = 10; // Use of undeclared identifier 'mData', why?
   return mData;
}

...
@end

Почему я получаю ошибку Complier:Use of undeclared identifier 'mData' внутри издевались getData() функционировать?

2 ответа

Решение

Вы неправильно понимаете, как работают методы и переменные экземпляра.

У каждого метода экземпляра есть переменная self который ссылается на текущий экземпляр (или "текущий объект") и использование переменной экземпляра, такой как mData, сокращение для доступа к этой переменной с помощью selfнапример, self->mData, где -> является оператором (Objective-)C для доступа к полю. Так что ваши setup Метод, написанный "длинной рукой":

-(void) setUp {
   [super setUp];
   self->mData = 0;
   self->store = [[Store alloc] init];
}

Но где же selfСсылка на экземпляр, сама взялась? Ну, это не волшебство, просто скрыто, оно передается методу экземпляра автоматически как скрытый дополнительный аргумент. На этом этапе, чтобы переключиться на псевдокод, чтобы показать это. Ваш setup Метод эффективно компилируется как:

-(void) setUp withSelf:(StoreTest *)self {
   [super setUp];
   self->mData = 0;
   self->store = [[Store alloc] init];
}

и вызов, такой как:

StoreTests *myStoreTests = ...

[myStoreTests setup];

эффективно компилируется как что-то вроде:

[myStoreTests setup withSelf:myStoreTests];

автоматическое добавление дополнительного self аргумент.

Теперь все вышесказанное относится только к методам и позволяет им обращаться к переменным и методам экземпляра, это не относится к простым функциям C - они не имеют скрытых self аргумент и не может получить доступ к переменным экземпляра.

Решение, которое вы упоминаете в ответе, который вы добавили mData вне интерфейса:

int mData;
@interface StoreTests : XCTestCase {
   Store *store;
}
@end

изменения mData в глобальную переменную, а не переменную экземпляра. Функции C могут обращаться к глобальным переменным. Однако это означает, что каждый экземпляр класса имеет одинаковые mData, здесь только один mData в этом случае, а не один для каждого экземпляра.

Поэтому превращение экземпляра переменной в глобальное не является общим решением для подобных проблем, однако маловероятно, что у вас будет более одного экземпляра вашего StoreTests класс это подходящее решение в этом случае.

Однако вы должны внести одно изменение: у вас может быть только одна глобальная переменная с заданным именем в программе, поэтому ваш mData должен быть уникальным и доступен любому коду в вашей программе, а не только коду StoreTests, Вы можете смягчить это, объявив переменную как static:

static int mData;

это сохраняет переменную как глобальную, но делает ее видимой только для кода в том же файле, что и объявление, которое, вероятно, является просто кодом StoreTests,

НТН

Я нашел одно решение для моего вопроса, то есть объявить mData выше @interface StoreTests : XCTestCase, что-то вроде этого:

int mData;
@interface StoreTests : XCTestCase {
    Store *store;
}
@end
...
Другие вопросы по тегам