Có cần thiết phải sử dụng autoreleasepool trong chương trình Swift không?


95

Trên trang 17 của bản trình bày WWDC14 này , nó nói

Làm việc với Objective-C? Vẫn phải quản lý bộ lưu trữ tự động lưu trữ hồ sơ tự động
{/ * mã * /}

Điều đó nghĩa là gì? Có nghĩa là nếu cơ sở mã của tôi không có bất kỳ tệp Objective-C nào, autoreleasepool {}là không cần thiết?

Trong câu trả lời của một câu hỏi liên quan , có một ví dụ autoreleasepoolcó thể hữu ích:

- (void)useALoadOfNumbers {
    for (int j = 0; j < 10000; ++j) {
        @autoreleasepool {
            for (int i = 0; i < 10000; ++i) {
                NSNumber *number = [NSNumber numberWithInt:(i+j)];
                NSLog(@"number = %p", number);
            }
        }
    }
}

Nếu đoạn mã trên được dịch sang Swift với autoreleasepooldrop, Swift có đủ thông minh để biết rằng numberbiến đó sẽ được phát hành sau lần đầu tiên }(giống như một số ngôn ngữ khác) không?


1
Dường như không có tài liệu nào về autoreleasepoolSwift. Tôi đã mở rộng câu hỏi của bạn và hỏi nó trong các diễn đàn nhà phát triển .
Aaron Brager,

Câu trả lời:


197

Các autoreleasepoolmô hình được sử dụng trong Swift khi trở về autoreleaseđối tượng (tạo ra bởi một trong hai đang Objective-C của bạn hoặc sử dụng các lớp Cocoa). Các autoreleasemẫu trong Swift chức năng giống như nó trong Objective-C. Ví dụ: hãy xem xét phiên bản Swift này của phương thức của bạn (khởi tạo NSImage/ UIImageđối tượng):

func useManyImages() {
    let filename = pathForResourceInBundle

    for _ in 0 ..< 5 {
        autoreleasepool {
            for _ in 0 ..< 1000 {
                let image = NSImage(contentsOfFile: filename)
            }
        }
    }
}

Nếu bạn chạy điều này trong Instruments, bạn sẽ thấy biểu đồ phân bổ như sau:

với autoreleasepool

Nhưng nếu bạn làm điều đó mà không có nhóm tự động khôi phục, bạn sẽ thấy rằng mức sử dụng bộ nhớ tối đa cao hơn:

không có bộ đệm tự động

autoreleasepoolcho phép bạn quản lý rõ ràng khi nào các đối tượng autorelease được phân bổ trong Swift, giống như bạn đã có thể làm trong Objective-C.

Lưu ý: Khi xử lý các đối tượng gốc Swift, bạn thường sẽ không nhận được các đối tượng autorelease. Đây là lý do tại sao bài thuyết trình đề cập đến cảnh báo về việc chỉ cần điều này khi "làm việc với Objective-C", mặc dù tôi ước Apple rõ ràng hơn về điểm này. Nhưng nếu bạn đang xử lý các đối tượng Objective-C (bao gồm cả các lớp Cocoa), chúng có thể là các đối tượng autorelease, trong trường hợp đó, việc biểu diễn Swift này của mẫu Objective-C @autoreleasepoolvẫn hữu ích.


2
Trên tất cả những câu hỏi này, bạn có thể viết lớp của riêng bạn, và nó có làm một printlntrong deinit, và nó trở nên khá dễ dàng để xác minh chính xác khi đối tượng được deallocated. Hoặc quan sát nó trong Instruments. Để trả lời cho câu hỏi của bạn, có vẻ như các đối tượng Swift được trả về từ các hàm có số lượng lưu giữ +1 (không phải đối tượng autorelease) và người gọi sẽ quản lý liền mạch quyền sở hữu từ thời điểm đó (ví dụ: nếu và khi đối tượng trả về nằm ngoài phạm vi, nó ngay lập tức được phân bổ, không được đặt trong một bộ đệm tự động).
Rob

3
@StevenHernandez Một hồ bơi tự động phát hiện có rất ít liên quan đến rò rỉ. Rò rỉ là do đối tượng chưa được phát hành. Mặt khác, Autorelease pool chỉ là một tập hợp các đối tượng mà việc phát hành được hoãn lại cho đến khi hết pool. Các hồ bơi không kiểm soát liệu thứ gì đó có được phân bổ hay không, mà chỉ đơn thuần là thời gian của việc phân bổ như vậy. Xem lại bản đồ, bạn không thể kiểm soát bộ nhớ đệm của nó (sử dụng bộ nhớ, nhưng không phải là rò rỉ thực sự) cũng như không làm bất cứ điều gì nếu có rò rỉ thực sự (và tôi không biết về bất kỳ rò rỉ chế độ xem bản đồ quan trọng nào, mặc dù trong lịch sử đã có rò rỉ ngẫu nhiên, khiêm tốn trong UIKit).
Rob

2
@matt Vâng, tôi đã thấy hành vi tương tự. Vì vậy, tôi đã lặp lại bài tập của mình với NSImage/ UIImageđối tượng và thể hiện vấn đề một cách nhất quán hơn (và, thành thật mà nói, đây là một ví dụ phổ biến hơn về vấn đề, vì việc sử dụng bộ nhớ tối đa thường chỉ có vấn đề khi xử lý các đối tượng lớn hơn; một ví dụ thực tế về điều này có thể là một thói quen thay đổi kích thước một loạt các hình ảnh). Tôi cũng tái tạo hành vi gọi mã Objective-C đã tạo rõ ràng các đối tượng autorelease. Đừng hiểu sai ý tôi: Tôi nghĩ rằng chúng ta cần các nhóm autorelease trong Swift ít thường xuyên hơn trong Objective-C, nhưng nó vẫn có một vai trò.
Rob

1
Tôi đã tìm thấy một ví dụ hoạt động! Chỉ cần gọi NSBundle's pathForResource:ofType:liên tục.
matt

1
pathForResource:ofType:Ví dụ của tôi không còn hoạt động trong Xcode 6.3 / Swift 1.2. :)
matt

4

Nếu bạn sử dụng nó trong mã Objective-C tương đương, thì bạn sẽ sử dụng nó trong Swift.

Swift có đủ thông minh để biết rằng biến số nên được phát hành sau lần đầu tiên}

Chỉ khi Objective-C có. Cả hai đều hoạt động theo các quy tắc quản lý bộ nhớ Cocoa.

Tất nhiên ARC biết rằng điều đó numbersẽ vượt ra khỏi phạm vi vào cuối lần lặp đó của vòng lặp và nếu nó giữ lại nó, nó sẽ giải phóng nó ở đó. Tuy nhiên, điều đó không cho bạn biết liệu đối tượng đã được tự động phát hành -[NSNumber numberWithInt:] hay chưa , vì có thể đã trả về một thể hiện đã được tự động phát hành hoặc chưa . Không có cách nào bạn có thể biết được, bởi vì bạn không có quyền truy cập vào nguồn của -[NSNumber numberWithInt:].


1
Nếu Swift hoạt động giống như Objective-C cho điều này, tại sao bản trình bày lại đề cập đến "Làm việc với Objective-C?" đặc biệt?
Ethan

9
@Ethan Có vẻ như các đối tượng Swift gốc không phải là đối tượng autorelease và autoreleasepoolcấu trúc này hoàn toàn không cần thiết. Nhưng nếu mã Swift của bạn đang xử lý các đối tượng Objective-C (bao gồm cả các đối tượng Cocoa), chúng tuân theo các mẫu autorelease, và do đó autoreleasepoolcấu trúc trở nên hữu ích.
Rob

Tôi hiểu rằng "Bộ đệm tự động cho phép bạn quản lý rõ ràng khi nào các đối tượng tự động vui lòng được phân bổ trong Swift" nhưng tại sao tôi lại muốn? Tại sao trình biên dịch không / không thể làm điều đó cho tôi? Tôi đã phải thêm bộ đệm tự động của riêng mình để giữ cho VM không đi qua mái nhà trong một vòng lặp chặt chẽ của các thao tác chuỗi khổng lồ. Đối với tôi, rõ ràng là nó nên được thêm vào, và nó hoạt động hoàn hảo. Tại sao trình biên dịch không thể làm điều đó? Trình biên dịch có thể trở nên thông minh hơn để làm tốt công việc của nó không?
vonlost
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.