Подтвердить что ты не робот

Переменные экземпляра Objective-C?

Я уверен, что мое замешательство здесь является результатом того, что я застрял в "мышлении Java" и не понимаю, как Obj-C отличается в этом случае.

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

MyClass {

  String myVar;

  MyClass() {
    // constructor
  }
}

В Obj-C я пытался сделать то же самое, объявив переменную только в файле .m следующим образом:

#import "MyClass.h"

@implementation MyClass

NSString *testVar;

@end

Я ожидал, что эта переменная имеет область действия, ограниченную этим классом. Поэтому я создал второй класс (идентичный):

#import "MySecondClass.h"

@implementation MySecondClass

NSString *testVar;

@end

То, что я вижу (и меня сбивает с толку), заключается в том, что изменение переменной в одном классе влияет на значение, видимое в другом классе. На самом деле, если я установлю точку останова, а затем "Перейти к определению" переменной, это приведет меня к

Я создал очень маленький проект XCode, который демонстрирует проблему здесь.

4b9b3361

Ответ 1

Измените это:

@implementation MyClass

NSString *testVar;

@end

в

@implementation MyClass {
    NSString *testVar;
}

// methods go here

@end

и вы получите то, что ожидали.

Как вы это делали, вы фактически создаете глобальную переменную. Две глобальные переменные были объединены в один компоновщиком, поэтому оба изменились при его установке. Переменная в фигурных скобках будет правильной (и частной) переменной экземпляра.

Изменить: после того, как я был никем без видимой причины, я подумал, что я бы указал на "старый" способ делать вещи и новый способ.

Старый способ:

SomeClass.h

@interface SomeClass : UIViewController <UITextFieldDelegate> {
    UITextField *_textField;
    BOOL _someBool;
}

@property (nonatomic, assign) BOOL someBool;

// a few method declarations

@end

SomeClass.m

@implementation SomeClass

@synthesize someBool = _someBool;

// the method implementations

@end

Теперь новый и улучшенный способ с помощью современного компилятора Objective-C:

SomeClass.h

@interface SomeClass : UIViewController

@property (nonatomic, assign) BOOL someBool;

// a few method declarations

@end

SomeClass.m

@interface SomeClass () <UITextFieldDelegate>
@end

@implementation SomeClass {
    UITextField *_textField;
}

// the method implementations

@end

Новый способ имеет несколько преимуществ. Основное преимущество заключается в том, что ни одна из конкретных сведений об этом классе не появляется в файле .h. Клиенту не нужно знать, какие делегаты нуждаются в реализации. Клиенту не нужно знать, какие ягоды я использую. Теперь, если для реализации нужен новый ivar или ему нужен новый протокол, файл .h не изменяется. Это означает, что меньше кода перекомпилируется. Это чище и намного эффективнее. Это также упрощает редактирование. Когда я редактирую файл .m и понимаю, что мне нужен новый ivar, внесите изменения в тот же .m файл, который я уже редактирую. Не нужно меняться взад и вперед.

Также обратите внимание, что для реализации больше не требуется ivar или @synthesize для свойства.

Ответ 2

В Java

MyClass {

  String myVar;
  MyClass() {
    // constructor
  }
}

В Objective-c

MyClass.h

@interface MyClass : NSObject{

      NSString* str; // Declaration
}
@end

MyClass.m

@implementation MyClass

  -(void)initializieTheString
  {
     //Defination 
  }

@end

Ответ 3

Что вы, вероятно, хотите (если вы не используете очень старую ОС и компилятор), просто используйте синтаксис свойств. То есть:.

@interface MyClass : NSObject

// method declarations here ...

@property (copy) NSString*    myVar;

// ... or here.

@end

Это сделает то, что вы намеревались сделать. Это будет неявно синтезировать переменную экземпляра и пару getter/setter для этой переменной. Если вы вручную хотели создать переменную экземпляра (вам вообще не нужно, если вам не нужен ваш код для работы на очень старых версиях MacOS), это то, что приведенный выше код делает под капотом для создания ivar:

@interface MyClass : NSObject
{
    NSString*    _myVar;
}

// method declarations here.

@end

Обратите внимание на фигурные скобки, которые сообщают компилятору, что это не просто глобальная переменная где-то между методами, а фактически переменная экземпляра, принадлежащая этому объекту.

Если вы создаете свойство только для внутреннего использования и не хотите, чтобы клиенты вашего класса могли его испортить, вы можете немного скрыть это во всем, кроме самых старых компиляторов ObjC, используя расширение класса, которое "продолжает" объявление класса из заголовка, но может быть выделено отдельно от него (обычно это в вашем файле реализации). Расширение класса выглядит как категория без имени:

@interface MyClass ()

@property (copy) NSString*    myVar;

@end

И вы можете либо разместить объявление собственности, либо даже объявления ivar (снова завернутые в фигурные скобки). Вы даже можете объявить то же свойство, что и readonly в интерфейсе класса, а затем повторно объявить его идентичным, но как readwrite в расширении, чтобы клиенты только его читали, но ваш код может его изменить.

Обратите внимание, что если вы не использовали ARC (то есть вы отключили значение по умолчанию для автоматического подсчета ссылок), вам нужно было бы установить все свои свойства в nil в вашем методе dealloc (кроме они установлены на weak или assign, конечно).

NB - все вышеперечисленные разделы @interface. Ваш фактический код перейдет в отдельные разделы @implementation. Таким образом, вы можете иметь заголовочные файлы (.h), которые вы можете передать своим клиентам класса, которые содержат только те части, которые вы им намереваетесь использовать, и скрыть детали реализации в файле реализации (.m), где вы можете изменить их, не беспокоясь о том, что кто-то случайно использовал их, и вы нарушите другой код.

PS - Обратите внимание, что NSStrings и другие объекты, которые вы хотите неизменным вкусом, но которые также существуют в изменяемом вкусе (т.е. NSMutableString), всегда должны быть copy свойствами, потому что это превратит NSMutableString в NSString, чтобы никто извне не мог изменить изменяемую строку под вами. Для всех других типов объектов вы обычно используете strong (или retain, если не ARC). Для вашего владельца класса (например, его делегата) вы обычно используете weak (или assign, если не ARC).

Ответ 4

В objective-c вы определяете переменную как конфиденциальную, делая так

MyClass.h

@interface MyClass : NSObject{

      NSString* _myTestVar; // Declaration
}
@end

и ссылаться на него в классе реализации, делая так MyClass.m

#import "MyClass.h";

@implementation MyClass

  -(void)initializieTheString
  {
     _myTestVar= @"foo"; //Initialization

  }

@end