Tới ARC hay không ARC? Những ưu và khuyết điểm là gì? [đóng cửa]


113

Tôi vẫn chưa sử dụng ARC, vì phần lớn mã trong dự án tôi đang làm vào lúc này được viết trước iOS 5.0.

Tôi chỉ tự hỏi, liệu sự tiện lợi của việc không giữ lại / phát hành theo cách thủ công (và có lẽ là mã đáng tin cậy hơn xuất hiện do đó?) Có vượt trội hơn bất kỳ 'chi phí' nào của việc sử dụng ARC không? Kinh nghiệm của bạn về ARC là gì và bạn có muốn giới thiệu nó không?

Vì thế:

  • ARC có thể mang lại bao nhiêu lợi ích cho một dự án?
  • ARC có chi phí như thu gom rác trong Java không?
  • Bạn đã sử dụng ARC chưa và nếu có, bạn đã tìm thấy nó như thế nào cho đến nay?

Không có thu gom rác trên ipad / ios. Bạn đang nói về OS X?
dasblinkenlight

1
Xin lỗi, tôi đang sử dụng các thuật ngữ Java không đúng chỗ. Ý tôi là với ARC, các đối tượng có thể được lưu giữ trong bộ nhớ lâu hơn mức cần thiết, sau đó được giải phóng thành một nhóm trong nhóm giải phóng tự động một thời gian sau. Đó là hiệu ứng này của chúng được giữ và phát hành với các đối tượng khác sau này, tương tự như bộ sưu tập rác của Java mà tôi đang đề cập đến.
Simon Withington

3
@TenementFunster, đối với cùng một mã (trừ các lệnh gọi để phát hành), ARC sẽ giữ đối tượng xung quanh không lâu hơn mã không phải ARC. Trong thực tế, nó thường sẽ phát hành nó sớm hơn bạn sẽ có. Có một số thứ chậm hơn một chút, nhưng chúng đã đẩy nhanh các mô hình chung đến mức làm giảm tác động hiệu suất. Đối với nhiều mẫu phổ biến (ví dụ: giữ lại một đối tượng đã được trả lại bằng autorelease), bạn thực sự không thể viết nó bằng tay nhanh như ARC sẽ làm nó tự động.
Rob Napier

1
Liên quan đến thu gom rác, hãy xem câu trả lời của tôi cho câu hỏi tương tự này: Sự khác biệt giữa đếm tham chiếu tự động Objective-C và thu gom rác là gì?
Brad Larson

Câu trả lời:


147

Không có nhược điểm. Sử dụng nó. Làm nó ngay hôm nay. Nó nhanh hơn mã cũ của bạn. Nó an toàn hơn mã cũ của bạn. Nó dễ dàng hơn mã cũ của bạn. Nó không phải là thu gom rác. Nó không có chi phí thời gian chạy GC. Trình biên dịch chèn giữ lại và phát hành ở tất cả những nơi bạn nên có. Nhưng nó thông minh hơn bạn và có thể tối ưu hóa những thứ không thực sự cần thiết (giống như nó có thể mở vòng lặp, loại bỏ các biến tạm thời, hàm nội tuyến, v.v.)

OK, bây giờ tôi sẽ cho bạn biết về những nhược điểm nhỏ:

  • Nếu bạn là nhà phát triển ObjC lâu năm, bạn sẽ giật mình trong khoảng một tuần khi nhìn thấy mã ARC. Bạn sẽ rất nhanh chóng vượt qua điều này.

  • Có một số (rất) phức tạp nhỏ trong việc bắc cầu với mã Core Foundation. Có một chút phức tạp hơn trong việc xử lý bất cứ thứ gì coi idlà một void*. Những thứ như mảng C idcó thể mất thêm một chút suy nghĩ để thực hiện chính xác. Việc xử lý lạ mắt đối với ObjC va_argscũng có thể gây ra rắc rối. Hầu hết những thứ liên quan đến toán học trên con trỏ objC phức tạp hơn. Bạn không nên có nhiều thứ này trong mọi trường hợp.

  • Bạn không thể đặt một idtrong một struct. Điều này khá hiếm, nhưng đôi khi nó được sử dụng để đóng gói dữ liệu.

  • Nếu bạn không tuân theo cách đặt tên KVC chính xác và trộn lẫn mã ARC và mã không phải ARC, bạn sẽ gặp sự cố về bộ nhớ. ARC sử dụng cách đặt tên KVC để đưa ra quyết định về quản lý bộ nhớ. Nếu tất cả đều là mã ARC, thì không vấn đề gì vì nó sẽ làm như nhau "sai" ở cả hai bên. Nhưng nếu đó là ARC hỗn hợp / không phải ARC thì sẽ có sự không phù hợp.

  • ARC sẽ làm rò rỉ bộ nhớ trong quá trình ném ngoại lệ ObjC. Một ngoại lệ của ObjC sẽ rất gần với thời điểm chấm dứt chương trình của bạn. Nếu bạn đang gặp phải một số lượng đáng kể các ngoại lệ objC, thì bạn đang sử dụng chúng không đúng cách. Điều này có thể sửa được bằng cách sử dụng -fobjc-arc-exceptions, nhưng nó phải chịu các hình phạt được thảo luận bên dưới:

  • ARC sẽ không làm rò rỉ bộ nhớ trong khi ném ngoại lệ ObjC hoặc C ++ trong mã ObjC ++, nhưng điều này phải trả giá bằng cả hiệu suất thời gian và không gian. Đây là một lý do khác trong danh sách dài các lý do để giảm thiểu việc sử dụng ObjC ++.

  • ARC sẽ hoàn toàn không hoạt động trên iPhoneOS 3 hoặc Mac OS X 10.5 trở xuống. (Điều này ngăn cản tôi sử dụng ARC trong nhiều dự án.)

  • __weakCon trỏ không hoạt động chính xác trên iOS 4 hoặc Mac OS X 10.6, điều này thật đáng tiếc, nhưng khá dễ dàng để khắc phục. __weakcon trỏ rất tuyệt, nhưng chúng không phải là điểm bán hàng số 1 của ARC.

Đối với hơn 95% mã ngoài đó, ARC là tuyệt vời và không có lý do gì để tránh nó (miễn là bạn có thể xử lý các hạn chế về phiên bản hệ điều hành). Đối với mã không phải ARC, bạn có thể chuyển -fno-objc-arctrên cơ sở từng tệp. Xcode không may làm cho việc này khó hơn nhiều so với thực tế. Bạn có thể nên chuyển mã không phải ARC vào một xcodeproj riêng biệt để đơn giản hóa việc này.

Tóm lại, hãy chuyển sang ARC ngay khi bạn có thể và không bao giờ nhìn lại.


BIÊN TẬP

Tôi đã thấy một vài nhận xét dọc theo dòng "sử dụng ARC không thể thay thế cho việc biết các quy tắc quản lý bộ nhớ Cocoa." Điều này hầu hết đúng, nhưng điều quan trọng là phải hiểu tại sao và tại sao không. Đầu tiên, nếu tất cả mã của bạn sử dụng ARC và bạn vi phạm Ba Phép thuậtở khắp nơi, bạn vẫn sẽ không gặp vấn đề gì. Nói thật là sốc, nhưng bạn hiểu rồi. ARC có thể giữ lại một số thứ mà bạn không muốn giữ lại, nhưng nó cũng sẽ giải phóng chúng, vì vậy điều đó sẽ không bao giờ thành vấn đề. Nếu hôm nay tôi đang dạy một lớp mới ở Cocoa, có lẽ tôi sẽ dành không quá năm phút cho các quy tắc quản lý bộ nhớ thực tế và có lẽ tôi sẽ chỉ đề cập đến các quy tắc đặt tên quản lý bộ nhớ trong khi thảo luận về việc đặt tên KVC. Với ARC, tôi tin rằng bạn thực sự có thể trở thành một lập trình viên mới bắt đầu tốt mà không cần học các quy tắc quản lý bộ nhớ.

Nhưng bạn không thể trở thành một lập trình viên trung cấp tốt. Bạn cần biết các quy tắc để kết nối chính xác với Core Foundation và mọi lập trình viên trung cấp cần phải đối phó với CF tại một số điểm. Và bạn cần biết các quy tắc cho mã hỗn hợp ARC / MRC. Và bạn cần biết các quy tắc khi bạn bắt đầu lộn xộn với các void*con trỏ tới id(mà bạn tiếp tục cần thực hiện KVO một cách chính xác). Và khối ... tốt, quản lý bộ nhớ khối thật kỳ lạ.

Vì vậy, quan điểm của tôi là việc quản lý bộ nhớ cơ bản vẫn quan trọng, nhưng nơi tôi đã từng dành thời gian đáng kể để nêu và đặt lại các quy tắc cho các lập trình viên mới, với ARC, nó đang trở thành một chủ đề nâng cao hơn. Tôi muốn các nhà phát triển mới suy nghĩ về đồ thị đối tượng hơn là lấp đầy đầu họ bằng những lời gọi cơ bản tới objc_retain().


3
Một điều cần hết sức cẩn thận (cả trong không phải ARC, nhưng hơn nữa trong ARC vì nó rất vô hình) là các chu kỳ lưu giữ. Lời khuyên của tôi ở đây là 1) nếu bạn thấy mình đang lưu trữ một khối objc dưới dạng một biến thể hiện, hãy xem xét kỹ nó để xem liệu nó có thể nắm bắt đối tượng mà nó là ivar hay không, thậm chí là gián tiếp. 2) Thực sự thiết kế đồ thị đối tượng của bạn, thay vì chỉ để nó xảy ra. Bạn phải biết những gì sở hữu những gì nếu bạn muốn viết mã tốt. 3) Sử dụng heapshots: friday.com/bbum/2010/10/17/...
Catfish_Man

1
@Catfish_Man Tất cả các điểm tốt. Giữ lại vòng lặp luôn là một vấn đề. Lời khuyên mới của Apple đúng như những gì bạn nói ở # 2. Chúng ta cần nghĩ về đồ thị đối tượng hơn là giữ lại và phát hành. # 1 là một vấn đề nghiêm trọng với khối và một trong số những lý do tôi thấy khối là một điều may mắn hỗn hợp cần được tiếp cận một cách thận trọng.
Rob Napier

2
Có một nhược điểm nghiêm trọng chưa được đề cập: khả năng tương thích chéo. Đối với chúng tôi, những linh hồn dũng cảm và ngu ngốc phải đối mặt với những vùng đất hoang được gọi là lập trình đa nền tảng, ARC đơn giản không phải là một lựa chọn, ít nhất là không cho đến khi GNU mở rộng trở lại các tính năng thời gian chạy và trình biên dịch của ObjC (họ nói rằng nhiều hơn thế nữa).
Rabbit

2
Bạn có thể sử dụng ARC ngoại trừ việc bạn cần hỗ trợ thiết bị iOS 3.x. BTW, hãy đảm bảo sử dụng Xcode để thực hiện quá trình chuyển đổi (Edit> Refactor> Convert to Objective-C ARC). Trong quá trình này, Xcode sẽ thực hiện rất nhiều xác thực để đảm bảo mã của bạn sẽ hoạt động và tìm ra bất kỳ mã nào vi phạm các nguyên tắc thiết kế đó.
ZhangChn

1
Tuyệt vời .. câu trả lời có điểm. đó là thứ 100 từ tôi. Congrates cho một thế kỷ;)
Ajay Sharma

20

Sẽ có nhiều câu trả lời kỹ thuật hơn, tốt hơn của tôi, nhưng đây là:

  • ARC! = Thu gom rác. Không có hình phạt thời gian chạy, nó được thực hiện tại thời gian biên dịch.
  • ARC also! = Chỉ tự động phát hành mọi thứ, như bạn đề xuất trong nhận xét của mình. Đọc tài liệu
  • Thật tuyệt vời khi bạn nhận ra mình đang thực hiện quản lý tham chiếu thủ công như thế nào
  • Sử dụng nó!
  • Một nhược điểm - việc duy trì mã cũ, không cung cấp đột nhiên trở nên rất tẻ nhạt.

Vâng, đó là lý do tại sao tôi không sử dụng nó cho đến nay - tôi không chắc mình có thể sử dụng số lượng đáng kể mã có từ trước của chúng tôi để chuyển đổi nó ... Tuy nhiên, tôi chắc chắn sẽ thử nó trong dự án tiếp theo. Cảm ơn câu trả lời của bạn :)
Simon Withington

Không phải là việc duy trì mã cũ trở nên khó khăn hơn, mà là kỳ vọng của bạn đã thay đổi. Vì vậy, không thực sự công bằng khi đổ lỗi cho ARC vì đã giúp cuộc sống dễ dàng hơn. Xcode giúp bạn dễ dàng chuyển đổi mã cũ sang ARC khi bạn đã sẵn sàng, nhưng rõ ràng là bạn không thể sử dụng nó nếu vẫn cần hỗ trợ các phiên bản iOS cũ hơn.
Caleb

1
@Caleb Tôi không đổ lỗi cho ARC, đó chỉ là nhược điểm duy nhất mà tôi thấy cho đến nay - nó làm tôi hư hỏng trong không gian của một dự án duy nhất.
jrturton

Vâng; Tôi không liệt kê đó là một vấn đề, nhưng có một vấn đề nhỏ là thoát khỏi thực hành quản lý bộ nhớ khi bạn phải chuyển đổi giữa các cơ sở mã. Một số dự án của tôi chạy trên 10.4, vì vậy tôi vẫn thực hiện rất nhiều công việc Objective-C 1.0 (vì vậy không có @synthesize, chứ đừng nói đến ARC). Nhưng bạn đã quen với việc chuyển đổi chế độ khá tốt.
Rob Napier

@jrturton Tôi nên nói rõ hơn rằng tôi đã viết điều đó vì lợi ích của OP và những độc giả trong tương lai, những người có thể không tìm hiểu ARC làm gì. Tôi biết chính xác ý của bạn, chỉ là không muốn bất kỳ ai đưa ra kết luận nhầm lẫn rằng việc trộn lẫn mã ARC và không phải ARC sẽ tạo ra một vấn đề.
Caleb

16

ARC có thể mang lại bao nhiêu lợi ích cho một dự án?

Lợi ích là mức độ bảo vệ đáng kể khỏi các lỗi quản lý bộ nhớ phổ biến. Rò rỉ do không thả vật thể và sự cố do không giữ lại hoặc giải phóng vật thể sớm sẽ giảm đáng kể. Bạn vẫn cần hiểu mô hình bộ nhớ được đếm tham chiếu để có thể phân loại các tham chiếu của mình là mạnh hay yếu, tránh các chu kỳ giữ lại, v.v.

Chi phí thu gom rác thực sự là bao nhiêu?

Không có bộ sưu tập rác trong iOS. ARC tương tự như GC ở chỗ bạn không phải giữ lại hoặc giải phóng các đối tượng theo cách thủ công. Nó không giống GC ở chỗ không có bộ thu gom rác. Mô hình giữ lại / phát hành vẫn được áp dụng, chỉ là trình biên dịch chèn các lệnh gọi quản lý bộ nhớ thích hợp vào mã của bạn cho bạn tại thời điểm biên dịch.

Bạn đã sử dụng ARC chưa và nếu có, bạn đã tìm thấy nó như thế nào cho đến nay?

Sẽ hơi bối rối nếu bạn đã quen với việc đếm tham chiếu, nhưng đó chỉ là vấn đề làm quen với nó và học cách tin tưởng rằng trình biên dịch thực sự sẽ làm đúng. Nó giống như sự tiếp tục của sự thay đổi đối với các thuộc tính đi kèm với Objective-C 2.0, đây là một bước tiến lớn khác nhằm đơn giản hóa việc quản lý bộ nhớ. Nếu không có lệnh gọi quản lý bộ nhớ thủ công, mã của bạn trở nên ngắn hơn và dễ đọc hơn một chút.

Vấn đề duy nhất với ARC là nó không được hỗ trợ trong các phiên bản iOS cũ hơn, vì vậy bạn cần tính đến điều đó trước khi quyết định áp dụng nó.


1
Có câu trả lời hay hơn mà tôi đang nói đến!
jrturton

1
Vâng, câu trả lời tuyệt vời. Vì vậy, thực sự không có nhược điểm nào đối với ARC ngoài việc phải học cách tin tưởng rằng nó hoạt động? Nó có vẻ quá tốt để trở thành sự thật trong trường hợp đó?
Simon Withington

4

Tôi nghĩ ARC là một ý tưởng tuyệt vời. So với GC, bạn có thể có bánh của bạn và ăn nó quá. Tôi có xu hướng tin rằng MRC áp đặt một 'kỷ luật' vô giá đối với việc quản lý bộ nhớ mà mọi người sẽ được hưởng lợi nếu có. Nhưng tôi cũng đồng ý rằng vấn đề thực sự cần lưu ý là Quyền sở hữu đối tượng và Đồ thị đối tượng (như nhiều người đã chỉ ra), chứ không phải số lượng tham chiếu cấp thấp.

Để kết luận: ARC KHÔNG phải là một thẻ miễn phí để không cần quan tâm đến bộ nhớ; nó là một công cụ để giúp con người tránh các tác vụ lặp đi lặp lại, gây căng thẳng và dễ bị lỗi, do đó, tốt hơn nên giao cho một máy (trong trường hợp này là trình biên dịch).

Điều đó nói rằng, cá nhân tôi là một nghệ nhân và vẫn chưa thực hiện được quá trình chuyển đổi. Tôi mới bắt đầu sử dụng Git ...

CẬP NHẬT: Vì vậy, tôi đã di chuyển toàn bộ trò chơi của mình, bao gồm thư viện gl và cho đến nay không có vấn đề gì (ngoại trừ với trợ lý di chuyển trong Xcode 4.2). Nếu bạn đang bắt đầu một dự án mới, hãy tiếp tục.


2

Tôi đã sử dụng nó trong một vài dự án (phải thừa nhận là nhỏ) và tôi chỉ có những trải nghiệm tốt, cả về hiệu suất và độ tin cậy đều khôn ngoan.

Một lưu ý nhỏ cần thận trọng là bạn cần tìm hiểu những điều nên làm và không nên: của những tham chiếu yếu để không gây ra bất kỳ vòng tham chiếu nào nếu bạn đang tự mã hóa giao diện người dùng của mình, nhà thiết kế có xu hướng làm tốt công việc đó tự động nếu bạn thiết lập GUI bằng cách sử dụng nó.


2

Nhược điểm duy nhất mà tôi gặp phải là nếu bạn sử dụng một thư viện có rất nhiều chức năng và dữ liệu CoreFoundation. Trong MRC, bạn không cần phải lo lắng về việc sử dụng một CFStringRefthay vì một NSString*. Trong ARC, bạn phải chỉ định cách cả hai tương tác (cầu nối cơ bản? Giải phóng đối tượng CoreFoundation và di chuyển nó sang ARC? Tạo đối tượng Cocoa làm đối tượng được giữ lại CoreFoundation +1?) Ngoài ra, trên OS X, nó chỉ khả dụng trên 64- mã bit (Mặc dù tôi có một tiêu đề hoạt động xung quanh đó…).

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.