Khi nào sử dụng -retainCount?


110

Tôi muốn biết bạn đã sử dụng trong tình huống nào -retainCountcho đến nay và cuối cùng là những vấn đề có thể xảy ra khi sử dụng nó.

Cảm ơn.


5
bạn không bao giờ nên sử dụng -retainCount.
holex

3
(Trừ khi bạn nên làm vậy. Đôi khi rất hữu ích để giúp hiểu những gì đang xảy ra, miễn là bạn đánh giá cao rằng đôi khi nó có thể gây hiểu lầm nghiêm trọng. Và tất nhiên, điều đó hoàn toàn không được phép nếu sử dụng ARC.)
Hot Licks

Câu trả lời:


243

Bạn không bao giờ nên sử dụng -retainCount, bởi vì nó không bao giờ cho bạn biết bất cứ điều gì hữu ích. Việc triển khai các khuôn khổ Foundation và AppKit / UIKit là không rõ ràng; bạn không biết những gì đang được giữ lại, tại sao nó được giữ lại, ai đang giữ lại nó, khi nào nó được giữ lại, v.v.

Ví dụ:

  • Bạn sẽ nghĩ rằng nó [NSNumber numberWithInt:1]sẽ có một retainCounttrong số 1. Nó không. Đó là 2.
  • Bạn sẽ nghĩ rằng nó @"Foo"sẽ có một retainCounttrong số 1. Nó không. Đó là 1152921504606846975.
  • Bạn sẽ nghĩ rằng nó [NSString stringWithString:@"Foo"]sẽ có một retainCounttrong số 1. Nó không. Một lần nữa, đó là 1152921504606846975.

Về cơ bản, vì bất cứ thứ gì cũng có thể giữ lại một đối tượng (và do đó thay đổi nó retainCount), và vì bạn không có nguồn của hầu hết mã chạy một ứng dụng, nên một đối tượng retainCountlà vô nghĩa.

Nếu bạn đang cố gắng tìm ra lý do tại sao một đối tượng không được phân bổ, hãy sử dụng công cụ Leaks trong Instruments. Nếu bạn đang cố gắng tìm ra lý do tại sao một đối tượng lại được định vị quá sớm, hãy sử dụng công cụ Zombies trong Instruments.

Nhưng không sử dụng -retainCount . Đó là một phương pháp thực sự vô giá trị.

biên tập

Xin mọi người vào http://bugreport.apple.com và yêu cầu-retainCount không dùng nữa. Càng nhiều người yêu cầu nó càng tốt.

chỉnh sửa # 2

Là một bản cập nhật, [NSNumber numberWithInt:1]hiện có retainCountmã là 9223372036854775807. Nếu mã của bạn mong đợi nó là 2, thì mã của bạn hiện đã bị hỏng.


4
Cảm ơn @ Dave-Delong về các ví dụ của bạn.
Moszi

1
KeepCount hiện hữu ích cho các singleton. (Bây giờ câu hỏi là các singleton hữu ích như thế nào ...) - (NSUInteger)retainCount{return NSUIntegerMax;}.
Joe

8
@Joe bạn có thể tạo một singleton mà không cần ghi đè retainCount.
Dave DeLong

5
@Joe Tôi biết điều đó; Google "target-c singleton" cho tất cả các cuộc thảo luận về lý do tại sao ví dụ đó không phải là một ví dụ rất tốt.
Dave DeLong

2
Một điều mà tôi sử dụng - @ DaveDeLong, bạn cũng có thể thấy điều này sai, nhưng tôi không nghĩ vậy - là ghi đè các deallocs và inits và đưa NSLog vào chúng (ngay cả với ARC). Điều này sẽ cho tôi một ý tưởng tuyệt vời cho dù đối tượng đang nhận được dealloced hay không, đó là câu hỏi thực sự chúng ta thường cố gắng để trả lời ..
Dan Rosenstark

50

KHÔNG BAO GIỜ!

Nghiêm túc. Đừng làm vậy.

Chỉ cần làm theo hướng dẫn quản lý bộ nhớ và chỉ phát hành những gì bạn alloc, newhoặc copy(hoặc bất cứ điều gì bạn gọi retainkhi ban đầu).

@bbum đã nói điều đó tốt nhất ở đây trên SO , và thậm chí còn chi tiết hơn trên blog của anh ấy .


8
Bởi vì bạn sẽ nghĩ rằng bạn đang đếm bộ nhớ, nhưng bạn sẽ làm sai.
Abizern

@Abizern - còn tình huống singleton ở một trong những câu trả lời khác thì sao?
Moszi

3
Để thêm vào điều này, bất kỳ thông tin nào bạn có thể nhận được từ -retainCount được (với nhiều chi tiết hơn) từ Instruments và các công cụ của nó.
Dave DeLong

3
Để thêm vào những gì Dave đã nói; số lượng giữ lại tuyệt đối của một đối tượng là một chi tiết triển khai. Cả một chi tiết bên trong của đối tượng và / hoặc một chi tiết của bất kỳ đối tượng nào khác mà đối tượng có thể đã đi qua. Gọi retain, retain, retain, autorelease, autorelease, autoreleasecó thể là một kết quả hoàn toàn hợp lệ của thông qua một đối tượng thông qua API UIKit, ví dụ.
bbum

2
@ d11wtq Nếu keepCount từng == 0, điểm kỳ dị đã đạt được!
bbum

14

Các đối tượng được phát hành tự động là một trường hợp mà việc kiểm tra -retainCount là không thông tin và có khả năng gây hiểu lầm. Số lượng lưu giữ không cho bạn biết về số lần -autorelease đã được gọi trên một đối tượng và do đó, nó sẽ được giải phóng bao nhiêu lần khi nhóm autorelease hiện tại cạn kiệt.


1
Cảm ơn - đây là một điểm tốt. Đây là câu trả lời đầu tiên thực sự có một lý do được mô tả tại sao không sử dụng KeepCount, bên cạnh từ "đừng" chung chung.
Moszi

1
@Moszi: Câu hỏi của bạn là "Khi nào thì sử dụng keepCount?" - nếu bạn không cố ý hỏi câu hỏi đó, bạn nên hỏi điều gì đó khác.
Chuck

@chuck - tôi thực sự quan tâm đến "khi nào thì sử dụng nó", tuy nhiên có vẻ như mọi câu trả lời sẽ là "không bao giờ" ... Nhưng - tôi đoán bạn đúng. Tôi sẽ để ngỏ câu hỏi trong vài ngày, và nếu không có câu trả lời nào khác thì không bao giờ, thì tôi sẽ chấp nhận câu trả lời là "không bao giờ".
Moszi

10

Tôi làm tìm retainCounts rất hữu ích khi kiểm tra sử dụng 'cụ'.

Sử dụng công cụ 'phân bổ', hãy đảm bảo rằng 'Số lượng tham chiếu bản ghi' được bật và bạn có thể truy cập vào bất kỳ đối tượng nào và xem lịch sử KeepCount của nó.

Bằng cách ghép nối các phân bổ và phát hành, bạn có thể có được bức tranh tốt về những gì đang diễn ra và thường giải quyết những trường hợp khó khăn khi một thứ gì đó không được phát hành.

Điều này chưa bao giờ khiến tôi thất vọng - bao gồm cả việc tìm ra lỗi trong các bản phát hành beta sớm của iOS.


5

Hãy xem tài liệu của Apple về NSObject, nó bao gồm khá nhiều câu hỏi của bạn: NSObject keepCount

Tóm lại, keepCount có thể vô dụng với bạn trừ khi bạn đã triển khai hệ thống đếm tham chiếu của riêng mình (và tôi gần như có thể đảm bảo rằng bạn sẽ không có).

Theo cách nói riêng của Apple, keepCount "thường không có giá trị gì trong việc gỡ lỗi các vấn đề quản lý bộ nhớ".


Trước hết cảm ơn bạn đã trả lời. Thông thường phản ứng của mọi người đối với câu hỏi này là "KHÔNG BAO GIỜ". (Xem câu trả lời). Thực ra "không có giá trị trong việc gỡ lỗi" không có nghĩa là "KHÔNG BAO GIỜ". Vì vậy, câu hỏi của tôi là - tại sao lại có cảm giác mạnh mẽ khi không sử dụng nó (ví dụ như trong triển khai singleton - một trong những câu trả lời)?
Moszi

Tôi đoán bạn sẽ cần cung cấp thêm thông tin về những gì bạn đang sử dụng nó. Theo đề xuất của Apple, việc sử dụng được chấp nhận là ghi đè số tiền giữ lại để triển khai hệ thống đếm tham chiếu của riêng bạn. Nhưng trong thực tế, bạn sẽ không bao giờ thấy điều đó (dù sao thì tôi cũng chưa bao giờ có). Phản ứng mạnh mẽ thường xuất phát từ thực tế là chính Apple đã ủng hộ (trong các nhóm thư của họ, tài liệu, diễn đàn nhà phát triển, v.v.) để giữ lại KeepCount một mình.
tiếp theo

1
@Moszi: Gỡ lỗi là tình huống duy nhất mà hầu hết mọi người có thể nghĩ rằng nó có giá trị, vì vậy nếu nó không đáng tin cậy ở đó, nó sẽ không bao giờ hữu ích. Bạn đang nghĩ đến cách sử dụng nào khác?
Chuck

4

Tất nhiên, bạn không bao giờ nên sử dụng phương thức keepCount trong mã của mình, vì ý nghĩa của giá trị của nó phụ thuộc vào số lượng tự động khôi phục đã được áp dụng cho đối tượng và đó là điều bạn không thể đoán trước được. Tuy nhiên, nó rất hữu ích để gỡ lỗi - đặc biệt là khi bạn đang tìm kiếm lỗi rò rỉ bộ nhớ trong mã gọi các phương thức của đối tượng Appkit bên ngoài vòng lặp sự kiện chính - và nó không nên bị phản đối.

Trong nỗ lực đưa ra quan điểm của mình, bạn đã phóng đại quá mức bản chất khó hiểu của giá trị. Đúng là nó không phải lúc nào cũng là số tham chiếu. Có một số giá trị đặc biệt được sử dụng cho cờ, chẳng hạn để chỉ ra rằng một đối tượng không bao giờ được phân bổ. Một số như 1152921504606846975 trông rất bí ẩn cho đến khi bạn viết nó dưới dạng hex và nhận được 0xfffffffffffffff. Và 9223372036854775807 là 0x7fffffffffffffffff trong hex. Và thực sự không quá ngạc nhiên khi ai đó chọn sử dụng các giá trị như thế này làm cờ, vì sẽ mất gần 3000 năm để có được Số tiền giữ lại cao bằng con số lớn hơn, giả sử bạn tăng Số lượng giữ lại 100.000.000 lần mỗi giây.


3

Bạn có thể gặp vấn đề gì khi sử dụng nó? Tất cả những gì nó làm là trả về số lượng giữ lại của đối tượng. Tôi chưa bao giờ gọi nó và không thể nghĩ ra bất kỳ lý do gì mà tôi muốn. Tôi đã ghi đè nó trong các đĩa đơn để đảm bảo rằng chúng không bị phân bổ.


2
Không có lý do gì để ghi đè nó trong trường hợp singleton. Không có đường dẫn mã nào trong Foundation / CoreFoundation dùng retainCountđể quản lý bộ nhớ.
bbum

Không phát hành sử dụng nó để quyết định xem nó có nên gọi dealloc không?
ughoavgfhw

2
Không; việc triển khai nội bộ của keep / release / autorelease có nguồn gốc sâu xa từ CoreFoundation và thực sự không hoàn toàn như những gì bạn có thể mong đợi. Hãy lấy nguồn CoreFoundation (nó có sẵn) và xem qua.
bbum

3

Bạn không nên lo lắng về việc bộ nhớ bị rò rỉ cho đến khi ứng dụng của bạn được thiết lập và chạy và làm điều gì đó hữu ích.

Khi đã có, hãy kích hoạt Instruments và sử dụng ứng dụng và xem liệu tình trạng rò rỉ bộ nhớ có thực sự xảy ra hay không. Trong hầu hết các trường hợp, bạn đã tự tạo một đối tượng (do đó bạn sở hữu nó) và quên giải phóng nó sau khi hoàn tất.

Đừng thử và tối ưu hóa mã của bạn khi bạn đang viết nó, những suy đoán của bạn về những gì có thể làm rò rỉ bộ nhớ hoặc mất quá nhiều thời gian thường sai khi bạn thực sự sử dụng ứng dụng bình thường.

Hãy thử và viết mã chính xác, ví dụ: nếu bạn tạo một đối tượng bằng phân bổ và tương tự, sau đó hãy đảm bảo rằng bạn phát hành nó đúng cách.


0

Bạn không bao giờ nên sử dụng nó trong mã của mình, nhưng nó chắc chắn có thể hữu ích khi gỡ lỗi


0

Không bao giờ sử dụng -retainCount trong mã của bạn. Tuy nhiên nếu bạn sử dụng, bạn sẽ không bao giờ thấy nó trả về số không. Hãy suy nghĩ về lý do tại sao. :-)


0

Các ví dụ được sử dụng trong bài đăng của Dave là NSNumber và NSStrings ... vì vậy, nếu bạn sử dụng một số lớp khác, chẳng hạn như UIViews, tôi chắc chắn rằng bạn sẽ nhận được câu trả lời chính xác (Số lượng giữ lại phụ thuộc vào việc triển khai và nó có thể dự đoán được).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.