2013-08-02 36 views
1

我正在尝试使用通讯录做一个关于联系人APP的程序,它工作正常,但是当我分析有几个内存泄漏时,我设法最大限度地减少内存泄漏,现在我下降到2个主要内存泄漏的警告,一个在我的地址簿重装功能,我已经包含的意见,看看什么所有的事情我都试过解决Xcode中的内存泄漏问题

-(void)reloadAddressBook 
{ 
    //if(self.addressBook) 
     //CFRelease(self.addressBook); 
    self.addressBook = (__bridge ABAddressBookRef) CFBridgingRelease(ABAddressBookCreate()); 

    if(ABAddressBookHasUnsavedChanges(self.addressBook)) 
    { 

     ABAddressBookSave(self.addressBook,NULL); 


    } 


    //if(self.contactAdd) 
     //CFRelease(self.contactAdd); 
    self.contactAdd= ABAddressBookCopyArrayOfAllPeople(self.addressBook); 


**//Memory warning here and says: call to function ABAddressBookCopyArrayOfAllPeople returns a core foundation object with a +1 retain count**  
     //self.contactAdd= (__bridge ABAddressBookRef) CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(self.addressBook)); 
     **// If I use this format my memory leak issue solves here but I get error in my program** 
    } 

- (void)viewDidLoad 
{**//Memory warning here and says :object leaked :allocated object is not retained lated in this execution path and has retain count +1** 
    [super viewDidLoad]; 

    self.contactSearchBar.delegate=self; 
    self.contactTableView.delegate=self; 
    self.contactTableView.dataSource=self; 

    UIBarButtonItem *addContactButton=[[UIBarButtonItem alloc]initWithTitle:@"Add" style:UIBarButtonItemStyleBordered target:self action:@selector(newContact:)]; 
    self.navigationItem.rightBarButtonItem=addContactButton; 
    [email protected]"My Contacts"; 


} 

另一个内存泄漏是在这个搜索栏功能

-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText 
{ 

    if(searchText.length==0) 
    { 
     isFiltered=NO; 

    } 
    else 
    { 
     isFiltered=YES; 

     int j=0,i=0; 
     self.filteredData= CFArrayCreateMutable(kCFAllocatorDefault, 0,&kCFTypeArrayCallBacks);**// Memory warning here and says: call to function CFArrayCreateMutable returns a core foundation object with a +1 retain count** 

     for(i=0;i<CFArrayGetCount(self.contactAdd);i++)**//Memory warning here and says :object leaked :allocated object is not retained lated in this execution path and has retain count +1** 
     { 
      self.person=CFArrayGetValueAtIndex(self.contactAdd,i); 
      NSString *str=[[NSString stringWithFormat:@"%@", (__bridge_transfer NSString *)ABRecordCopyValue(self.person, kABPersonFirstNameProperty)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 
      NSRange contactRange= [str rangeOfString: searchText options:NSCaseInsensitiveSearch]; 

      NSLog(@"i=%d, j=%d",i,j); 

      if(contactRange.location!=NSNotFound) 
      { 
       CFArrayInsertValueAtIndex(self.filteredData,j++,self.person); 
       CFArrayGetValueAtIndex(self.filteredData,j-1); 
      } 

     } 
     //CFRelease(self.contactAdd); 
    //CFRelease(self.filteredData); 
    }  

内存泄漏秀在for循环语句,它说:

+1

非常类似于这个问题:http://stackoverflow.com/questions/18010276/potential-memory-leak-abaddressbookcopyarrayofallpeople – borrrden

+0

当你说“分配的对象没有保留在这个执行路径中[sic]”,你是指“引用”还是“释放”?如果您已经拥有+1,那么没有理由建议保留它。 (更一般地,请复制并粘贴问题导航器中的警告,而不是尝试重新键入它们。) –

+0

“如果使用此格式,我的内存泄漏问题在此解决,但我在程序中遇到错误”什么错误? –

回答

1

就像我在my answer on your other question提到释放,持有对象时,通常还拥有引用,除非另有声明它们in Core Foundation, Create and Copy functions return an ownership reference.

属性(通常与weak)。这意味着,在这样一个说法:

self.filteredData= CFArrayCreateMutable(…); 

您现在拥有的对象两次:一次是因为你创造了它,一旦因为你的财产保留它。

您通常应该只拥有每个属性,ivar或其他强引用(如局部变量)的每个对象。任何额外的所有权(例如创建和复制功能)都是您需要清理的东西,这就是为什么最好尽可能少地在CF域中进行清理:ARC会为您清理所有内容,但它不会触及CF除非你告诉它的东西。

说到属性和局部变量,您不需要将所有内容都设置为属性。搜索代码中的person应该是该方法中的局部变量,因为这是该搜索状态的一部分,而不是您的对象需要无限期保留的内容。你已经有str作为局部变量,所以我不确定你为什么使用person的属性。

你告诉ARC通过桥梁与CF世界互动蒙上:

  • __bridge_transfer(或CFBridgingRelease)告诉ARC“收拾这个所有权我,当我用它做”。
  • __bridge_retained(或CFBridgingRetain)告诉ARC“我要把这个物体扔进CF-land;不要放过它,直到我另外说“(然后你必须在转移或立即执行CFRelease时做到这一点)。

而且,您通常希望将事情从CF世界中解放出来,让ARC尽可能地处理它们。

因此,我建议使self.filteredData是一个NSMutableArray,而不是CFMutableArray。使用Foundation创建数组意味着它已经处于ARC的控制之下,不需要桥接它。

对于self.contactAdd,您可以在检索它时桥接到NSArray,然后将其视为NSArray。这包括使用快速枚举而不是索引来遍历它,或者更好的是,使用谓词搜索而不是自己遍历它。 (我不会指望能够与ABPersons一起工作的内置比较谓词,但这就是predicateWithBlock:的用途。)

您搜索代码的基于谓词的版本看起来像这样(极其未测试) :

self.filteredData = [self.contactAdd filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings){ 
    ABPersonRef person = (__bridge ABPersonRef)evaluatedObject; 
    NSString *firstName = [[NSString stringWithFormat:@"%@", (__bridge_transfer NSString *)ABRecordCopyValue(self.person, kABPersonFirstNameProperty)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 

    NSRange contactRange = [str rangeOfString:searchText options:NSCaseInsensitiveSearch]; 
    return (contactRange.location != NSNotFound); 
}]; 

(该块,并且基于它的谓词,返回每个对象是否匹配filteredArrayUsingPredicate:创建包含每个的量,谓词评价true对象阵列。)

一件事:你有没有考虑过使用ABPeoplePickerNavigationControll呃?

+0

我能够解决通过使用self.addressBook的_addressbook不是问题。所有的问题走在Xcode 4.6,但_addressbook犯规似乎在4.2工作,但桥的释放似乎对版本。而对于你的另一个问题,是我已经使用ABPeoplePickerNavigationController做了同样的事情,它运行良好,我只是想要tr在另一种使用CFArray的方法中,感谢您的支持 :) – Gamerlegend

0

很明显,您在viewDidLoad的末尾缺少[addContactButton release]。另外,为什么CFRelease的电话会被注释掉?他们应该平衡CFArrayCreateMutable

关于self.contactAdd - 如果它被定义为“retain”属性,请不要直接为其分配返回值ABAddressBookCopyArrayOfAllPeople。相反,实例化一个局部变量,其分配给属性,然后使用CFRelease

+0

[addContactButton release]不是必需的,因为它的ARC,即使我尝试添加它,ARC也禁止它。如果添加了CFRelease,我会得到消息,该属性返回+0保留计数的核心基础对象。我曾尝试ABAddressBookCopyArrayOfAllPeople的价值分配给另一个变量,并警告会消失,但我得到一个运行时错误:( – Gamerlegend

+0

对不起,你没有提到ARC – Stavash

+0

self.contactAdd =(__ bridge_retained CFArrayRef)CFBridgingRelease(contactAddtemp);我能。解决另一个变量的帮助下,第一次警告,这个bridgerelease功能,但第二次警告仍犯规走沿 – Gamerlegend