Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: [ios] revert memory leak fix removal #103

Merged
merged 1 commit into from
Mar 27, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 60 additions & 33 deletions super_native_extensions/rust/src/darwin/ios/drag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,28 +145,11 @@ impl Session {
let drag_item: id = msg_send![drag_item, autorelease];
let () = msg_send![drag_item, setLocalObject: local_object.into_objc().autorelease()];

let configuration = self.configuration.borrow();
let item = &configuration.items[index];
if item.lift_image.is_some() {
// separate lift image means we need to register preview provider for drag image
let image = self.image_view_for_item(index, ImageType::Drag);
let shadow_path = bezier_path_for_alpha(&item.image.image_data);
let provider = ConcreteBlock::new(move || {
let parameters: id = msg_send![class!(UIDragPreviewParameters), new];
let () = msg_send![parameters, autorelease];
let clear_color: id = msg_send![class!(UIColor), clearColor];
let () = msg_send![parameters, setBackgroundColor: clear_color];
let () = msg_send![parameters, setShadowPath: *shadow_path];

let image = image.clone().autorelease();
let preview: id = msg_send![class!(UIDragPreview), alloc];
let () = msg_send![preview, initWithView:image parameters: parameters];
let () = msg_send![preview, autorelease];
preview
});
let provider = provider.copy();

let () = msg_send![drag_item, setPreviewProvider: &*provider];
// Setting preview provider here leaks entire session if drag is cancelled before
// lift is complete. So instead we set it later in `will_begin`. After `will_begin`
// it is safe to set preview provider as it will be picked immediately and won't leak.
if self.in_progress.get() {
self.set_preview_provider(drag_item);
}

drag_item
Expand Down Expand Up @@ -235,8 +218,47 @@ impl Session {
}
}

fn drag_will_begin(&self) {
unsafe fn set_preview_provider(&self, item: id) {
let preview_provider: id = msg_send![item, previewProvider];
// If lift image is specified now create preview provider for dragging.
// If this is done when creating items the whole session leaks...
if preview_provider.is_null() {
let (index, _) = PlatformDragContext::item_info(item);
let configuration = self.configuration.borrow();
let drag_item = &configuration.items[index];
if drag_item.lift_image.is_none() {
return;
}
let image = self.image_view_for_item(index, ImageType::Drag);
let shadow_path = bezier_path_for_alpha(&drag_item.image.image_data);
let provider = ConcreteBlock::new(move || {
let parameters: id = msg_send![class!(UIDragPreviewParameters), new];
let () = msg_send![parameters, autorelease];
let clear_color: id = msg_send![class!(UIColor), clearColor];
let () = msg_send![parameters, setBackgroundColor: clear_color];
let () = msg_send![parameters, setShadowPath: *shadow_path];
let image = image.clone().autorelease();
let preview: id = msg_send![class!(UIDragPreview), alloc];
let () = msg_send![preview, initWithView:image parameters: parameters];
let () = msg_send![preview, autorelease];
preview
});
let provider = provider.copy();

let () = msg_send![item, setPreviewProvider: &*provider];
}
}

fn drag_will_begin(&self, session: id) {
self.in_progress.replace(true);
unsafe {
// workaround for memory leak, see [create_item].
let items: id = msg_send![session, items];
for i in 0..NSArray::count(items) {
let item = NSArray::objectAtIndex(items, i);
self.set_preview_provider(item);
}
}
}

fn did_move(&self, _session: id, location: Point) {
Expand Down Expand Up @@ -300,13 +322,14 @@ impl Session {
}
}

fn preview_for_item(&self, index: usize) -> id {
fn preview_for_item_type(&self, index: usize, ty: ImageType) -> id {
let configuration = self.configuration.borrow();
let drag_image = configuration.items[index]
.lift_image
.as_ref()
.unwrap_or(&configuration.items[index].image);
let image_view = self.image_view_for_item(index, ImageType::Lift);
let item = &configuration.items[index];
let drag_image = match ty {
ImageType::Lift => item.lift_image.as_ref().unwrap_or(&item.image),
ImageType::Drag => &item.image,
};
let image_view = self.image_view_for_item(index, ty);
unsafe {
let parameters: id = msg_send![class!(UIDragPreviewParameters), new];
let () = msg_send![parameters, autorelease];
Expand All @@ -329,6 +352,10 @@ impl Session {
}
}

fn preview_for_item(&self, index: usize) -> id {
self.preview_for_item_type(index, ImageType::Lift)
}

fn preview_for_canceling(&self, index: usize) -> id {
let view_container = self.view_container.clone();
// Fade the container view out. UIKit seems to keep the view
Expand Down Expand Up @@ -360,7 +387,7 @@ impl Session {
})
.detach();

self.preview_for_item(index)
self.preview_for_item_type(index, ImageType::Lift)
}
}

Expand Down Expand Up @@ -552,9 +579,9 @@ impl PlatformDragContext {
Self::get_session_id(session).and_then(|id| self.sessions.borrow().get(&id).cloned())
}

fn drag_will_begin(&self, _interaction: id, session: id) {
if let Some(session) = self.get_session(session) {
session.drag_will_begin();
fn drag_will_begin(&self, _interaction: id, platform_session: id) {
if let Some(session) = self.get_session(platform_session) {
session.drag_will_begin(platform_session);
}
}

Expand Down