Unresponsive app when stopping a Thread using copyItemMT (MacOS)

In an app created to ingest video files to a NAS using NSFileManagerMBS, I have this code in a subclass of Desktop Container in a Thread named “CopyThread”:

For i As Integer = 0 To FilesToCopy.Count - 1
  Var FileName As String = FilesToCopy(i).NameWithoutExtensionMBS
  Var ext As String = FilesToCopy(i).NameExtensionMBS
  Var NewName As String = FileName + AddRandomToName + "." + ext
  Var e As NSErrorMBS
  
  NowCopying = NowCopying + 1
  CurrentFile = FilesToCopy(i).Name
  
  If not NSFileManagerMBS.defaultManager.copyItemMT(FilesToCopy(i), DestinationFolder.Child(NewName), e) Then
    Error = e.LocalizedDescription
  Else
    LastFileCopied = LastFileCopied + 1
  End if
Next

Finished = True

The app has four of these “Ingest Containers” and everything works perfectly and the app is responsive even while ingesting multiple files simultaneously.
The problem is that if I want to stop an ingest and send the command “CopyThread.Stop” to one of these threads, the app becomes unresponsive and I get a beach ball until the current file is copied.
Some of these video files are several GBs so it may take some time before the app becomes responsive again.
Can this be avoided?

You can’t simply stop such a thread.
You may need to add a property “cancel as boolean”, set it to true. And in the for loop check the cancel flag to exit the loop if needed quickly.

You may also want to hide the window/container if you like the user interface to update.

If you need something you can cancel, please check MacFileOperationMBS class.

I’ve tried the MacFileOperationMBS class and the files get copied, but it seems like the event StatusChanged never fires.

I wonder why?

Code in Thread:

For i As Integer = 0 To FilesToCopy.Count - 1
  
  Var source, dest as FolderItem
  Var m As new MyFileOperation
  Var FileName As String = FilesToCopy(i).NameWithoutExtensionMBS
  Var ext As String = FilesToCopy(i).NameExtensionMBS
  Var NewName As String = FileName + AddRandomToName + "." + ext
  
  source=FilesToCopy(i)
  dest=DestinationFolder
  
  m.CopyObject(source, dest, NewName, m.kFSFileOperationDefaultOptions,5.0)
  
  System.DebugLog("Error: "+str(m.LastError))
  
Next

Finished = True

Code in the event StatusChanged in MyFileOperation:

Var path as string

if status.CurrentItem<>nil then
  path=status.CurrentItem.UnixpathMBS
end if

System.DebugLog("Status Changed: "+StageString(status.Stage)+", Error: "+str(status.Error)+", Current Item: "+path)
System.DebugLog(FormatItems(status.ObjectsComplete)+" of "+FormatItems(status.TotalObjects)+", "+FormatItems(status.ObjectsRemaining)+" remaining.")

System.DebugLog("Hello from StatusChanged")

please try the example file “MacFileUtil async”, which seems to work fine here.

Maybe this is due you not keeping the MyFileOperation object around.
Especially since CopyObject is asynchron and will return before being finished!

I’ve already tried the asynchron example and it works perfectly well.
But I’m not copying a directory. I’m copying an array of folderitems and I couldn’t make that work.

Does MakeFileOperationMBS work for arrays of FolderItems?

Well, it can work in your situation.
You loop over your array and start each copy process.

Then you wait for the copy to finish.
Your code makes a loop to sleep the threads for 0.1 seconds until status property reports the copy to be finished.

Thanks, Christian.

I’ll give it a try and see if I can make it work.

Will report back.

Unfortunately, lack of time has prevented me from experimenting further with MacFileOperationMBS.
I have chosen your idea with a “Cancel as Boolean” and it works fine. However, you have to wait for the current transfer to finish - but the app is responsive and you can continue working in the other “Ingest Containers”.
Thanks for your help