何时使用目标C中的属性?

我在这里有一个问题: 在iPhone应用程序混淆双免费错误消息/内存泄漏 ,我认为需要一个新的问题来回答它。

我感兴趣的代码是在这个问题,但我会重新发布在这里

#import <UIKit/UIKit.h> #import "MyManager.h" @interface ListOfCarShares : UITableViewController <NSXMLParserDelegate> { NSURLConnection *connection; NSMutableData *carsharexml; NSMutableArray *ldestination; NSMutableArray *ldeparts_from; NSMutableArray *lcs_id; NSMutableArray *ltime; NSMutableString *currentElement; NSMutableString *tdest; NSMutableString *tfrom; NSMutableString *ttime; NSMutableString *tid; } -(void)fetchcarshares; @property (nonatomic, assign) IBOutlet UITableViewCell *maincell; @end #import "ListOfCarShares.h" @implementation ListOfCarShares @synthesize maincell; - (id)initWithStyle:(UITableViewStyle)style { self = [super initWithStyle:style]; if (self) { // Custom initialization } return self; } - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict { currentElement = [[elementName copy] autorelease]; if ([elementName isEqualToString:@"destination"]) { //NSLog(@"found current conditions tag it reads %@",currentElement); tdest = [[NSMutableString alloc] init]; } if ([elementName isEqualToString:@"departs_from"]) { tfrom = [[NSMutableString alloc] init]; } if ([elementName isEqualToString:@"time"]) { ttime = [[NSMutableString alloc] init]; } if ([elementName isEqualToString:@"cs_id"]) { tid = [[NSMutableString alloc] init]; } } - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { if ([currentElement isEqualToString:@"destination"]) { [tdest appendString:string]; } if ([currentElement isEqualToString:@"departs_from"]) { [tfrom appendString:string]; } if ([currentElement isEqualToString:@"time"]) { [ttime appendString:string]; } if ([currentElement isEqualToString:@"cs_id"]) { [tid appendString:string]; } } - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { if ([currentElement isEqualToString:@"destination"]) { [ldestination addObject:tdest]; [tdest release]; } if ([currentElement isEqualToString:@"departs_from"]) { [ldeparts_from addObject:tfrom]; [tfrom release]; } if ([currentElement isEqualToString:@"time"]) { [ltime addObject:ttime]; [ttime release]; } if ([currentElement isEqualToString:@"cs_id"]) { [lcs_id addObject:tid]; [tid release]; } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; // Uncomment the following line to preserve selection between presentations. // self.clearsSelectionOnViewWillAppear = NO; // Uncomment the following line to display an Edit button in the navigation bar for this view controller. // self.navigationItem.rightBarButtonItem = self.editButtonItem; } - (void)viewDidUnload { [super viewDidUnload]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; ldestination = [[NSMutableArray alloc] init]; ldeparts_from = [[NSMutableArray alloc] init]; ltime = [[NSMutableArray alloc] init]; lcs_id = [[NSMutableArray alloc] init]; carsharexml = [[NSMutableData alloc] init]; [self fetchcarshares]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [connection release]; [ldestination release]; [ldeparts_from release]; [ltime release]; [lcs_id release]; /// [carsharexml release]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES for supported orientations return (interfaceOrientation == UIInterfaceOrientationPortrait); } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. return [ltime count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil]; if (cell == nil) { [[NSBundle mainBundle] loadNibNamed:@"carsharecell" owner:self options:nil]; } // Configure the cell... cell=maincell; UILabel *from; UILabel *dest; UILabel *time; from = (UILabel *)[cell viewWithTag:4]; dest = (UILabel *)[cell viewWithTag:5]; time = (UILabel *)[cell viewWithTag:6]; from.text=[ldeparts_from objectAtIndex:indexPath.row]; dest.text=[ldestination objectAtIndex:indexPath.row]; time.text=[ltime objectAtIndex:indexPath.row]; return cell; } /* // Override to support conditional editing of the table view. - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { // Return NO if you do not want the specified item to be editable. return YES; } */ /* // Override to support editing the table view. - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // Delete the row from the data source [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; } else if (editingStyle == UITableViewCellEditingStyleInsert) { // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view } } */ /* // Override to support rearranging the table view. - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { } */ /* // Override to support conditional rearranging of the table view. - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { // Return NO if you do not want the item to be re-orderable. return YES; } */ -(void)fetchcarshares { MyManager *sharedManager = [MyManager sharedManager]; NSString *urlString = [NSString stringWithFormat:@"http://url/get.php?username=%@&password=%@",sharedManager.user,sharedManager.passw]; NSURL *url = [NSURL URLWithString:urlString]; NSURLRequest *req = [NSURLRequest requestWithURL:url]; connection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES]; } -(void) connection:(NSURLConnection *)conn didReceiveData:(NSData *)data { [carsharexml appendData:data]; } -(void) connectionDidFinishLoading:(NSURLConnection *)conn { NSString *xmlcheck = [[NSString alloc] initWithData:carsharexml encoding:NSUTF8StringEncoding]; NSLog(@"%@",xmlcheck); [xmlcheck release]; NSXMLParser *parser = [[NSXMLParser alloc] initWithData: carsharexml]; [parser setDelegate:self]; [parser parse]; [parser release]; [[self tableView] reloadData]; } -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 102; } #pragma mark - Table view delegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { } -(void)dealloc { [super dealloc]; } @end 

我只在.h文件中定义了一个属性。 回答这个问题的人似乎认为,我有双重自由错误的原因是因为我没有我的variables@property

我有很多代码几乎相同,我没有问题。

我的问题是

  1. 我应该什么时候使用财产?
  2. 我应该在这里使用属性,为什么?

谢谢

从技术上讲,只需要使用属性来设置其他类可以访问的值,但是很多人发现对于所有指针types的实例variables使用(保留)属性更容易,所以保留有点自动化。 (然后使用self.propertyName = xxx;表示设置, self.propertyName = nil;释放dealloc 。)

是的,你可以保留并“手动”发布,但是这样做很麻烦,而且当你进行“快速编辑”时,你往往会搞砸了一些东西。 但是,你必须注意的一件事是为self.xxx属性指定一个保留的(不是​​简单的自动维护的)值(比如你的alloc/init值)。 这将导致双重保留,如果你不以某种方式缓解。

如果你不使用属性,另一件事情是在你release它之后总是nil指针值。 这可以防止您意外地使用发布的值,并防止您执行双重release

(请注意,使用上面描述的“懒惰”技术绝对不是“糟糕的编程”,而是“完美地”搞清楚所有的东西。大约98%的编程是debugging,而且你可以做任何事情来防止错误或使其更容易find是善良。)

(我还会注意到,在上面的代码中,你的问题似乎主要是在释放它们之后,你不会tdest指针,而你的iftesting应该在使用之前检查指针是否被删除。 )

补充:请注意,上述内容适用于ARC之前的程序。 随着ARC的“规则”大幅改变。

属性做了很多事情。 在最肤浅的层面上,他们让你以虚线的forms访问你的成员variables。 充其量,他们可以成为优秀的内存pipe理工具(等等)。

假设你有一个variables:

 NSNumber * myNumber; 

在代码的后面,你可以这样访问它:

 myNumber = [NSNumber numberWithInt: 5]; 

问题是,您可能会失去对myNumber中以前存储的值的引用。 可能的内存泄漏! 此时,myNumber上没有保留,在使用前可能会解除分配。

物业如何帮助? 假设您定义了一个属性并使用合成:

在界面定义中:

 NSNumber * myNumber; ... @property (retain, nonatomic) NSNumber * myNumber; 

在执行文件中:

 @synthesize myNumber; 

这将创build一个getter和setter。 含义…每当你把myNumber分配给某个东西,如:

 self.myNumber = newNumber; 

下面的setter方法(通过合成指令创build)被调用:

 - (NSNumber *) setMyNumber: (NSNumber *) newNumber { [myNumber release]; myNumber = newNumber; [myNumber retain]; return newNumber; } 

在这里,myNumber自动获得一个保留。 每次手工操作都非常繁琐,正如你所看到的,使用属性要容易得多。

不过这仍然不是一个完美的解决scheme! 为什么? 如果在实现中使用以下语句会怎样?

 myNumber = newNumber; 

请记住,属性的getter和setter只有在使用虚线符号( self.myNumber )时才会被调用。 所以在这里,使用属性对我们来说什么都没有做,因为我们忘了使用它们! 这是非常普遍的,可能会失效,并且令人感到沮丧。

那么,最好的方法是什么? 这是我推荐的(就像其他人一样):

在接口类中:

 NSNumber * _myNumber; ... @property (retain, nonatomic) NSNumber * myNumber; 

在执行文件中:

 @synthesize myNumber = _myNumber; 

现在,您可以访问您的号码为:

 self.myNumber = whateverNewNumber; 

但是,如果你这样做了:

 myNumber = whateverNewNumber; 

你会得到一个错误…因为myNumbervariables不存在…迫使你每次使用self.myNumber

另外,如果你select走这条路线,不要忘记dealloc:

 - (void) dealloc { [_myNumber release]; _myNumber = nil; } 

或更简洁:

 - (void) dealloc { self.myNumber = nil; }