2013-02-08 24 views
14

Tôi đang làm việc với Box2D (C++) và tôi tạo đối tượng Objective-C và gán nó cho thuộc tính userData của cơ thể Box2D, thuộc loại void*.Làm thế nào để lưu trữ an toàn đối tượng id trong thành phần void C++ * trong ARC khi không có tham chiếu nào khác giữ đối tượng?

Hiện tại trong một số trường hợp, void* userData có thể là tham chiếu hoạt động duy nhất cho đối tượng ObjC đó. Do đó, vì tôi đã sử dụng (__bridge void*) trong nhiệm vụ, ARC sẽ cho phép nó đi. Đó là điều tôi cần sửa.

Tôi đã cân nhắc các tùy chọn để ngăn điều này xảy ra? Tôi đọc Clang's ARC documentation, đặc biệt là các bộ phận về đúc cầu (cũng như Q & A trên SO) cũng như gật đầu với các cấu trúc đúc cầu khác nhau mà chúng coi là "hình thành không đúng".

Tuy nhiên, suy nghĩ đầu tiên của tôi là sử dụng (__bridge_retained void*) trong gán ban đầu cho userData. Nhưng điều đó khiến tôi băn khoăn làm thế nào để cân bằng được sự giữ lại đó? Tôi rõ ràng không thể gửi bản phát hành cho đối tượng.

Vì vậy, tôi có phải CFRelease() đối tượng không? Hay nó cần phải là CFBridgingRelease()? Hoặc cả hai đều là bất hợp pháp ở đây?

Có phải là (__bridge_transfer void*) truyền từ userData sang loại id tạm thời đủ, có lẽ trong khi đặt userData thành NULL sau đó? Đó có phải là một ý tưởng hay không?

Tôi biết cách thay thế sẽ là giữ riêng một đối tượng userData cho các đối tượng userData và giữ chúng đồng bộ với tuổi thọ của thân Box2D, thêm và xóa chúng đồng bộ với thân Box2D của chúng. Tuy nhiên, điều này cảm thấy như quá mức cần thiết vì ở đây tôi biết những gì tôi đang làm, tôi biết tôi cần phải +1 đối tượng miễn là cơ thể Box2D hoạt động, và -1 đối tượng khi cơ thể Box2D được lấy ra. Ngoài ra, tôi biết rằng chỉ có hai phương thức mà các đối tượng Box2D được thêm vào và loại bỏ, và truy cập trực tiếp vào userData thậm chí không thể trong khung của tôi vì tất cả các đối tượng Box2D được ẩn đằng sau các giao diện/trình bao Objective-C.

Thiết lập có thể "không thành hình" sang một bên, bạn sẽ khuyên bạn nên làm gì trong tình huống này?

+0

@Emil: cảm ơn bạn đã sửa mã nội tuyến, tôi chỉ muốn tự làm. – LearnCocos2D

+2

Không có vấn đề gì, tôi phải thừa nhận rằng thật lạ khi chỉnh sửa một thứ tầm thường như vậy trong bài đăng của người dùng 20k! Ha: D – Emil

+0

vâng đôi khi tôi hỏi những câu hỏi thực sự khó hiểu :) – LearnCocos2D

Trả lời

23

__bridge_retained có nghĩa là "Gửi đối tượng ARC này ra khỏi vùng đất không có ARC bằng cách giữ lại". Bạn gọi nó khi bạn cần tạo "void *" không được theo dõi. Vì vậy, trong trường hợp của bạn, userData = (__bridge_retained void *)obj.

__bridge_transfer có nghĩa là "Kéo đối tượng này trở lại từ vùng đất không có ARC bằng cách giải phóng nó". Bạn gọi điều này khi bạn muốn vô hiệu hóa hiệu quả số void *. Vì vậy, obj = (__bridge_transfer id)userData. Sau đó, con trỏ userData không an toàn để sử dụng; thay vào đó, bạn chỉ làm việc với obj. Khi obj vượt quá phạm vi, ARC sẽ phát hành nó lần cuối. Điều này có thể đòi hỏi phải tạo tạm thời id chỉ cho mục đích này.

Vì vậy, trong trường hợp của bạn, bạn muốn sử dụng __bridge_retained khi bạn gửi vật thể đó vào Box2D và sử dụng __bridge_transfer khi bạn muốn vô hiệu hóa userData. Nếu bạn cần truy cập userData làm đối tượng Objective-C nhưng không làm mất hiệu lực con trỏ, hãy sử dụng plain __bridge.

+2

Tuyệt vời, giải thích rõ ràng, +1. –

+1

Tốt. Tôi chủ yếu nhầm lẫn về việc đưa nó trở lại bởi vì nó dường như không "làm bất cứ điều gì" với đối tượng, trong khi thực tế nó có. Phong cách-khôn ngoan Tôi nghĩ rằng tôi sẽ thích: CFBridgingRelease (body-> GetUserData()) tiếp theo là body-> SetUserData (NULL). Từ những gì tôi hiểu đó là điều tương tự như __bridge_transfer cast. – LearnCocos2D

+0

Tôi thực sự sẽ sử dụng '__bridge_ *' bản thân mình, bởi vì điều này không thực sự quan tâm CF trong bất kỳ cách nào. – nneonneo

2

Bạn hiểu nhầm tác giả của tài liệu có ý nghĩa gì đối với "hình thành không đúng".Đây là vô hình thành:

NSData* data; // Initialized 
NSData* data2= (__bridge NSData*) data; 

Ngoài này là vô hình thành:

void* data; // Initialized 
void* data2= (__bridge void*) data; 

Đây không phải là vô hình thành:

NSData* data; // Initialized 
void* data2= (__bridge void*) data; 

Được không vô hình thành là đủ mà giá trị bên trái có thể giữ lại và giá trị đúng không thể giữ lại hoặc ngược lại. Vì vậy, trong trường hợp của bạn bạn đang đúc đối tượng trỏ đến con trỏ thô và viceversa, cách tiếp cận của bạn là chính xác.

Tại vị trí của bạn, tôi sẽ triển khai một con trỏ thông minh gửi thông báo CFBridgingRetain về xây dựng và thông báo CFBridgingRelease về việc hủy.

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