Skip to content

Commit

Permalink
fix: [ios] revert memory leak fix removal (#103)
Browse files Browse the repository at this point in the history
  • Loading branch information
knopp committed Mar 27, 2023
1 parent dcd29e7 commit c3035f6
Showing 1 changed file with 60 additions and 33 deletions.
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

0 comments on commit c3035f6

Please sign in to comment.