iPhone实例变量问题

时间:2012-03-19 13:51:04

标签: iphone ios ios4 object

我试图找出将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

4 个答案:

答案 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 managementDeclared 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?

它可能对你有帮助。