Свойство класса object-C должно добавить «self» при назначении его значения - PullRequest
0 голосов
/ 19 ноября 2010

Я новичок здесь, и уже искал похожие статьи типа «Нужно ли« я »? и «Установка свойства класса Objective-C без использования собственной ссылки» Однако я все еще не могу получить четкий ответ, который может объяснить мой случай.

У меня есть простой класс, и у моего интерфейса есть два текстовых поля и одна кнопка, вот код:


@interface testViewController : UIViewController {
    NSString       *teststring_A;
    NSString       *teststring_B;
    IBOutlet UITextField *textfield_1;
    IBOutlet UITextField *textfield_2;
}
@property (nonatomic, retain) NSString *teststring_A;
@property (nonatomic, retain) NSString *teststring_B;
- (IBAction)action1:(id)sender;
- (IBAction)action2:(id)sender;
@end

@implementation testViewController
@synthesize teststring_A;
@synthesize teststring_B;

- (void)dealloc {
    [super dealloc];
}
- (IBAction)action1:sender
{
    teststring_A = textfield_1.text ;
    NSLog(@"teststring_A in action 1 is : %@\n", teststring_A);

    teststring_B = textfield_2.text ;
    NSLog(@"teststring_B in action 1 is : %@\n", teststring_B);
}
- (IBAction)action2:(id)sender
{
 NSLog(@"teststring_A in action 2 is : %@\n", teststring_A);
 NSLog(@"teststring_B in action 2 is : %@\n", teststring_B);
}
 

вывод:


2010-11-19 15:32:14.827 test[419:207] teststring_A in action 1 is : 123
2010-11-19 15:32:14.829 test[419:207] teststring_B in action 1 is : 456
2010-11-19 15:32:14.927 test[419:207] teststring_A in action 2 is : 123
2010-11-19 15:32:14.929 test[419:207] teststring_B in action 2 is : {(
    >
)}

 

И при нажатии кнопки сначала запускается действие1, а затем действие2. Моя проблема ... в action2 значение teststring_B становится неправильным, иногда приложение даже падает. Что меня смущает, так это (1), почему значение testtring_A правильное ??? (2) teststring_B назначается textfield_2.text, который не создается с помощью alloc, поэтому предположим, что указатель должен существовать постоянно. тогда почему значение testtring_B становится неверным в action2 ??? (3) в dealloc я должен выпустить teststring_A и teststring_B, верно? (я так думаю)

Все, что я знаю, это если я добавлю «self», например «self.teststring_B = textfield_2.text;» тогда не будет проблем. значение будет правильным. Поэтому я хотел бы знать техническую причину.

Ответы [ 3 ]

1 голос
/ 19 ноября 2010

Вы путаете переменные и свойства . Свойства поддерживаются переменными, но на самом деле они являются методами.

Здесь вы определяете свойство с именем teststring_B, которое сохраняет все, что ему присвоено (и освобождает старое значение). Эквивалентные методы выглядят так (упрощенно):

- (NSString *)teststring_B {
    // Return the content of the variable teststring_B.
    return teststring_B;
}

- (void)setTeststring_B:(NSString *)val {
    // Retain new value.
    [val retain];
    // Release old value in variable teststring_B
    [teststring_B release];
    // Assign the new, retained value to variable teststring_B
    teststring_B = val;
}

Теперь вы можете использовать свойство двумя способами: либо с [self setTeststring_B:foo];, либо с self.teststring_B = foo;. Важным моментом является то, что последний является просто удобным способом написания, компилятор переведет его в первую форму, то есть компилятор превратит строки self.foo = bar; в [self setFoo:bar];.

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

Теперь назначенное значение было автоматически освобождено (оно не знало, что переменная все еще указывает на него), и позже новый объект ожил в том же месте памяти (если вам повезло). В любом случае, переменная teststring_B теперь указывает не на текст, как вы думали, а на какой-то случайный объект (или мусор).

Есть два способа исправить это:

// First retain, then release; it might be the same object
// and if you would release it first its retain count might
// drop to 0 and get cleaned up before you can retain it again.
NSString *tmp = [textfield_2.text retain];
[teststring_B release];
teststring_B = tmp;

// Better !
self.teststring_B = textfield_2.text;
0 голосов
/ 19 ноября 2010

То, что вы делаете сейчас, это простое задание.Это может вызвать сбой, если объект, на который указывает teststring_A или teststring_B, освобожден;это также называется висячей ссылкой.

Причина, по которой происходит только простое назначение, заключается в том, что вы не обращаетесь к сеттерам через семантику @property;вы можете получить retain для этих NSString объектов, выполнив self.teststring_A = textfield_1.text.

Однако вы должны использовать copy со свойствами NSString. См .: Свойство NSString: скопировать или сохранить?

Другими словами, вы хотите это:

@property (nonatomic, copy) NSString *teststring_A;
@property (nonatomic, copy) NSString *teststring_B;

и это:

self.teststring_A = textfield_1.text ;
self.teststring_B = textfield_1.text ;
0 голосов
/ 19 ноября 2010

Доступ к переменной напрямую без использования self не сохранит ее.Поэтому при последующем доступе к ней переменная автоматически освобождается и вызывает сбой приложения.

, поэтому вы можете написать

1) [self setTeststring_B:textfield_2.text]; or
2) the dot syntax self.teststring_B = textfield_2.text; or
3) teststring_b = [textfield_2.text retain]
...