我试图找出将myString合成到实例变量_myString的目的是什么。
这样做的目的是什么?我倾向于注意到很多人这样做。
此外,我应该释放实例变量并将实例变量设置为nil,这是正确的。
ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
{
NSString *_myString;
}
@property (nonatomic, retain) NSString *myString;
@end
ViewController.m
#import "ViewController.h"
@implementation ViewController
@synthesize myString = _myString;
- (void)viewDidLoad
{
[super viewDidLoad];
self.myString = [[NSString alloc] initWithFormat:@"Hello"];
_myString = [[NSString alloc] initWithFormat:@"Goodbye"];
NSLog(@"%@\t%@", self.myString, _myString);
}
- (void)viewDidUnload
{
_myString = nil;
[super viewDidUnload];
}
- (void)dealloc
{
[_myString release];
[super dealloc];
}
@end
答案 0 :(得分:3)
当你在目标c中@synthesize一个对象类型属性时,编译器将为该实例变量生成两个隐藏方法。因此,当您引用myObject.myString
时,不仅会返回_myString的指针,还会调用生成的- (NSString*) myString
方法。同样,如果您为属性分配了一些内容:myObject.myString = @"foo";
它将被编译为[myObject setMyString:@"foo"];
。
- (NSString*) myString
和- (void) setMyString:(NSString*) theString
中的内容取决于您在声明属性时指定的关键字。最常见的是assign
,它简单地指定你给出的指针:
- (void) setMyString:(NSString*) theString
{
_myString = theString;
}
- (NSString*) myString
{
return _myString;
}
这与声明_myString是一个公共变量并没有多大区别,但是更明确的方式是说可以从外部直接访问这个变量。
反过来,retain
生成类似的setter方法(getter方法将是相同的):
- (void) setMyString:(NSString*) theString
{
[theString retain];
[_myString release];
_myString = theString;
}
您可以看到,它负责传递给属性的对象的内存管理。换句话说,您可以确定在您拥有该对象之前不会释放该对象,因此当您取得其所有权时,您不必手动retain
它。这使得编写管理内存而没有泄漏的代码变得更加方便。请注意,在dealloc中,您仍然必须将nil应用于您的属性才能释放它存储的最后一个对象。
另一类属性,当它们的数据不是来自实例变量而是来自某些其他数据源(如数据库)时。例如,核心数据的托管对象的自动生成属性可以正常工作。
最后,您还可以定义自己的getter和setter。例如,围绕一些常用的NSUserDefaults
设置编写属性包装器是个好主意,这将有助于其访问:
@interface Bar
@property (nonatomic, assign) NSString* foo;
@end
@implementation Bar
- (void) setFoo:(NSString *)theFoo
{
[[NSUserDefaults standardUserDefaults] setObject:theFoo
forKey:@"settings.foo"];
}
- (NSString*) foo
{
return [[NSUserDefaults standardUserDefaults]
stringForKey:@"settings.foo"];
}
@end
myBar.foo = @"foobar"; // automatically persisted between application runs
另请阅读这些内容:Advanced memory management和Declared properties in objective C
答案 1 :(得分:1)
self.myString(技术上是[self myString])实际上通过这个对象中的函数来访问和设置ivar _myString:
-(NSString *)myString {
// code that is automatically generated by the @synthesize statement OR
// code that you write which over-rides the generated accessor.
// both of which generally return the value stored in _myString
}
-(void)setMyString:(NSString *)newString{
// code that generally changes the value of _myString
}
直接使用_myString绕过这些函数并直接访问ivar。
答案 2 :(得分:0)
人们倾向于综合属性来强调前缀变量,而不是在编写其他代码时误认为两者。例如:
// ... do sth
myString = @"Foo";
// ... do sth else ...
self.myString = @"Bar";
第一条指令直接访问变量,第二条指令使用合成的setter。在不指向特定变量的情况下进行合成时,将为您创建与该属性同名的变量:
@synghesize myString; // this creates myString variable for you
人们不是这样做,而是创建下划线前缀变量,以避免错误地直接访问它。当他们这样做时,第一条指令myString = @"Foo"
不再编译,这使得很容易防止像你错误地绕过getter或setter那样令人讨厌的错误。
关于第二个问题,请尽可能使用ARC。如果没有,您应该首先释放变量,然后重置指针。在您提供的代码中,viewDidUnload将比dealloc更早被调用,因此您将发生内存泄漏,因为_myString将在调用release之前指向nil。
答案 3 :(得分:0)
声明可以区分对象中的私有变量和公共变量。 这完全是可选的。
请参阅:When is UIViewController viewDidUnload called?和 What exactly must I do in viewDidUnload?
它可能对你有帮助。