2011-02-10 29 views
5

"Rò rỉ tiềm ẩn của đối tượng được phân bổ trên dòng n và được lưu trữ trong 'biến số'."Cảnh báo phân tích tĩnh Xcode Clang này có thể bị chặn như thế nào?

Thông thường đây là cảnh báo phân tích rất hữu ích, nhưng có một vài trường hợp mà tôi nhận được các phản hồi giả gây phiền nhiễu mà tôi muốn ngăn chặn để giữ cho kết quả phân tích của tôi sạch sẽ. Trong sự bảo vệ của nhà phân tích, những gì nó nhận thấy chắc chắn sẽ là một rò rỉ bộ nhớ là nó không cho một bản phát hành trong một con đường thực hiện (mà nó bị mù).

Tôi sẽ giải thích thêm về tình huống của mình. Nó xảy ra ở nhiều hương vị khác nhau, nhưng mẫu chung như sau:

  1. Một đối tượng được phân bổ và đại biểu của nó được đặt.
  2. Một cái gì đó được thực hiện với đối tượng. (Một nhiệm vụ bắt đầu, một khung nhìn được hiển thị, vv).
  3. Thực hiện phương pháp hiện tại sẽ kết thúc. (Nhập cảnh báo Clang).
  4. Đối tượng quyết định nhiệm vụ của nó đã hoàn thành, gửi ủy quyền một tin nhắn.
  5. Đại biểu phát hành đối tượng.

Đây không phải là một mẫu thiết kế bí truyền, vì vậy tôi hy vọng có thể ngăn chặn được sự đàn áp. Tôi biết nó có thể tránh được bằng cách lưu trữ các đối tượng vi phạm trong một ivar sau đó được phát hành, nhưng tôi rất thích không thêm ô nhiễm ivar.

+0

Nó đánh tôi là kỳ quặc khi đại biểu của đối tượng giữ lại nó. Thông thường, một đối tượng giữ lại nó là đại biểu, và để cho đại biểu giữ lại đối tượng sẽ tạo một chu trình giữ lại. Tôi không nói có trường hợp ZERO nơi một đại biểu có thể muốn giữ lại (có lẽ ngắn ngủi) đối tượng, nhưng nó có vẻ có liên quan để biết tại sao đó là trường hợp ở đây. Từ những gì được nói ở đây, tôi muốn nói rằng nó kosher nhiều hơn cho các đối tượng để giữ lại chính nó trong thời gian hoạt động và tin nhắn đại biểu tiếp theo hơn cho các đại biểu để "mất quyền sở hữu" phân bổ/init ngụ ý giữ lại. – ipmcc

+0

@ipmcc: Mặc dù một đối tượng có thể giữ lại đại biểu của mình và có một vài nơi trong SDK nơi một lớp làm điều đó, tôi cho rằng lưu trữ đại biểu là yếu tố phổ biến hơn, để tránh giữ lại chu kỳ bạn đề cập. Dù bằng cách nào, nó chắc chắn không phải là "điển hình" cho một đối tượng để giữ lại đại biểu của nó. Trong trường hợp của tôi, một số lớp đã tạo một đối tượng có phân bổ/init và đặt chính nó làm đại biểu. Là chủ sở hữu của lớp, đại biểu sau đó phát hành đối tượng khi nó được thực hiện. Không có quyền sở hữu nào xảy ra ở đây. –

+0

@ipmcc - Matt là đúng, mẫu bình thường là: Object A tạo đối tượng B và đặt chính nó làm đại biểu của đối tượng B. Đối tượng A giữ lại đối tượng B. Khi đối tượng A bị dealloced, nó chắc chắn để unset chính nó như là đại biểu của đối tượng B, nếu không bạn có thể sụp đổ. – DougW

Trả lời

6

Clang có một vài mới Source Annotations. Cụ thể, bạn có thể quan tâm đến thuộc tính ns_consumed.

+0

Điều này dường như chỉ là những gì tôi đang tìm kiếm, tuy nhiên attribute_ns_consumed dường như không có sẵn: __has_feature (attribute_ns_consumed) trả về false. Tài liệu mà trang web của bạn đặc biệt gọi chúng là Chú thích API Mac OS X. Những thứ này không có sẵn trên iOS phải không? –

+0

Việc đặt tên là một chút sai lệch, nó thực sự có nghĩa là Chú thích API Cocoa. Và 'ns_consumed' là khá mới. Tôi không nghĩ rằng Clang 1.6 có chúng (phiên bản được chuyển với Xcode 3.2), nhưng tôi hy vọng Clang 2.0 sẽ làm gì (tôi chưa thử nghiệm). –

+0

Tôi đang sử dụng 2.0 và không có súc sắc. Không may ... –

1

Tôi nghĩ bạn nên chú ý đến thông báo phân tích tĩnh trong trường hợp này. Mẫu của bạn có các vấn đề tiềm ẩn.

Cụ thể, khi bạn quay trở lại từ phương thức được gọi để thực hiện bước 5, bạn đang ở trong một phương pháp của một đối tượng có thể đã được deallocated. Tôi giải thích mô hình một cái gì đó của bạn như thế này:

// steps 1, 2, 3 
-(void) methodThatCreatesObject 
{ 
    id theObj = [[TheObj alloc] init]; 
    [theObj setDelegate: delegateObj]; 
    // other stuff 
} 

Lưu ý các vi phạm trên memory management rules

// step 4 - a method of theObj 
-(void) someMethod 
{ 
    [delegate notifyTaskCompleteFromObj: self]; 
    // self points to an invalid object here. Doing anything with self results in EXC_BAD_ACCESS 
} 

Các vi phạm trên một giả định được nêu trong quy chế quản lý bộ nhớ:

Một nhận đối tượng là thường được bảo đảm duy trì hợp lệ trong phương thức nhận được trong

nếu chúng ta nói self là một đối tượng nhận được, nó là về mặt kỹ thuật, vì nó được truyền như một tham số trên ngăn xếp.

// step 5 the delegate method defined in the delegate object 

-(void) notifyTaskCompleteFromObj: (TheObj*) anObj 
{ 
    // do stuff 
    [anObj release]; 
} 

Ở trên cũng vi phạm các quy tắc quản lý bộ nhớ.

Mẫu thông thường là có bộ điều khiển sở hữu cả đại biểu và đối tượng có đại biểu (thường là bộ điều khiển chính nó là đại biểu). Tôi nghĩ bạn nên chuyển sang mô hình đó.

+0

Nếu đó là hình mẫu của tôi, tôi sẽ đồng ý với bạn. Tôi cho rằng sự khái quát hóa của tôi đã để lại quá nhiều chỗ cho việc giải thích. Dưới đây là một ví dụ cụ thể về chính xác những gì đang diễn ra: Trong một phương thức của đối tượng điều khiển, một đối tượng khác (yêu cầu mạng tùy chỉnh) được cấp phát và đại biểu được đặt thành tự, chứ không phải đối tượng khác. Vì vậy, bộ điều khiển sở hữu đối tượng mà nó hoạt động như đại biểu. Sau đó, khi nhận được thông báo từ yêu cầu mạng, bộ điều khiển sẽ đưa ra yêu cầu. Không có vi phạm; Tôi không giao trách nhiệm cho một đối tượng khác. –

+0

@Matt: Bạn có nói rằng 'theObj' trong ví dụ của tôi là một biến mẫu không? – JeremyP

+0

Không, không phải.Tôi có thể giữ một tham chiếu đến nó như là một ivar để phát hành nó sau này, nhưng vì theObj chuyển một tham chiếu đến chính nó trong thông điệp của đại biểu, tôi chọn để giải phóng tham chiếu được truyền như một tham số của thông điệp chứ không phải thêm một ivar chỉ để phát hành nó. Việc thiếu tham chiếu đến Thebj là chính xác những gì các nhà phân tích không thích mặc dù. –

0

Một tùy chọn thú vị khác ở đây đã xảy ra với tôi. OP đã đưa ra kịch bản sau:

  1. Một đối tượng được phân bổ và đại biểu của nó được đặt.
  2. Một cái gì đó được thực hiện với đối tượng. (Một nhiệm vụ bắt đầu, một khung nhìn được hiển thị, vv).
  3. Thực hiện phương pháp hiện tại sẽ kết thúc. (Nhập cảnh báo Clang).
  4. Đối tượng quyết định nhiệm vụ của nó đã hoàn thành, gửi ủy quyền một tin nhắn.
  5. Đại biểu phát hành đối tượng.

Nếu, thay vì một phiên bản rõ ràng, bạn chỉ muốn kéo dài tuổi thọ của đối tượng được phân bổ cho rằng các đối tượng phân bổ/delegeate, bạn có thể để điều này:

TheObject* foo = [[TheObject alloc] init] autorelease]; 
foo.delegate = self; 
[foo doSomething]; 
objc_setAssociatedObject(self, foo, foo, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
return; 

Bằng cách đặt foo như một đối tượng liên kết với chính sách lưu giữ, người được ủy quyền (self) sẽ giữ lại một cách hiệu quả đối tượng mà sau đó sẽ được giải phóng bất cứ khi nào đại biểu (self) được dealloced (sau này).

Nó không chính xác những gì OP yêu cầu, nhưng nó là một mô hình hữu ích dù sao, và cảm thấy như nó có lẽ sẽ đủ trong tình hình OP trình bày.

Các vấn đề liên quan