Использование необъявленной ошибки идентификатора в моем случае
Мой код вызывает функцию библиотеки 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
...