Copy Files with Progress Bar

Hi Ya!

I’m trying to work with this obj-c class I found that copies files with progress (see below). The copy function works fine and I can see the progress in the log, but I can’t figure out how to get the delegate methods to work. What I really want are values that I can bind to a progress bar. It looks like the class has the values I need, just can’t figure out how to get to them.

If you’re willing to take pity on me and help me out I’d really appreciate it. :smiley:

I’d also appreciate any other ideas or examples to get a usable progress bar for copying files. I’ve seen a few on here, but it didn’t look like they’re up to date.

I’ve been using the counter method, but since I’m working with large files copied to a network share and it looks like the interface is frozen since it’s only incrementing after each copy. I’ve also tried using the Finder which has everything I’d like in the interface, but it’s not ideal.

Please let me know if there’s anything I can do or provide to make this and easy fix.

Thanks so much!!!

Here’s the delegate script.



--  AppDelegate.applescript
--  FileCopy

script AppDelegate
	property parent : class "NSObject"
	
	-- IBOutlets
	property theWindow : missing value
	property IDCopyUtils : missing value
	property progressBar : missing value
	property sourcePath : missing value
	property targetPath : missing value
	
	on applicationWillFinishLaunching:aNotification
		set sourcePath to current application's NSString's stringWithString:"/Users/johnappleseed/Desktop/Test/Test.zip"
		set targetPath to current application's NSString's stringWithString:"/Users/johnappleseed/Desktop/Test.zip"
		IDCopyUtils's setDelegate:me
	end applicationWillFinishLaunching:
	
	on applicationDidFinishLaunching:(aNotification)
		IDCopyUtils's copyFileAtPath:sourcePath toPath:targetPath
	end applicationDidFinishLaunching:
	
	(*
        on setCopyProgress:() -- causes EXC_BAD_ACCESS

        end setCopyProgress:
        *)
	
	on didFinishedCopyWithError:{}
		
	end didFinishedCopyWithError:
	
	on applicationShouldTerminate:sender
		return current application's NSTerminateNow
	end applicationShouldTerminate:
	
end script

Here’s what the log returns:
[format]
2016-04-30 10:43:30.736 FileCopy[6791:487712] Size: 0.000000
2016-04-30 10:43:30.793 FileCopy[6791:487712] Size: 0.000000
2016-04-30 10:43:30.895 FileCopy[6791:487712] Size: 0.000000
2016-04-30 10:43:30.995 FileCopy[6791:487712] Size: 0.000000
2016-04-30 10:43:31.095 FileCopy[6791:487712] Size: 0.000000
2016-04-30 10:43:31.194 FileCopy[6791:487712] Size: 0.000000
2016-04-30 10:43:31.295 FileCopy[6791:487712] Size: 0.023654
2016-04-30 10:43:31.399 FileCopy[6791:487712] Size: 0.040858
2016-04-30 10:43:31.495 FileCopy[6791:487712] Size: 0.058061
2016-04-30 10:43:31.594 FileCopy[6791:487712] Size: 0.075264
2016-04-30 10:43:31.694 FileCopy[6791:487712] Size: 0.086016
2016-04-30 10:43:31.793 FileCopy[6791:487712] Size: 0.098918
2016-04-30 10:43:31.896 FileCopy[6791:487712] Size: 0.111821
2016-04-30 10:43:31.994 FileCopy[6791:487712] Size: 0.131174
2016-04-30 10:43:32.098 FileCopy[6791:487712] Size: 0.141926
2016-04-30 10:43:32.196 FileCopy[6791:487712] Size: 0.154829
2016-04-30 10:43:32.294 FileCopy[6791:487712] Size: 0.174182
2016-04-30 10:43:32.396 FileCopy[6791:487712] Size: 0.191385
2016-04-30 10:43:32.494 FileCopy[6791:487712] Size: 0.206438
2016-04-30 10:43:32.595 FileCopy[6791:487712] Size: 0.223641
2016-04-30 10:43:32.694 FileCopy[6791:487712] Size: 0.242995
2016-04-30 10:43:32.799 FileCopy[6791:487712] Size: 0.260198
2016-04-30 10:43:32.894 FileCopy[6791:487712] Size: 0.277401
2016-04-30 10:43:32.998 FileCopy[6791:487712] Size: 0.292454
2016-04-30 10:43:33.095 FileCopy[6791:487712] Size: 0.313958
2016-04-30 10:43:33.195 FileCopy[6791:487712] Size: 0.331161
2016-04-30 10:43:33.295 FileCopy[6791:487712] Size: 0.348364
2016-04-30 10:43:33.395 FileCopy[6791:487712] Size: 0.363417
2016-04-30 10:43:33.494 FileCopy[6791:487712] Size: 0.387071
2016-04-30 10:43:33.595 FileCopy[6791:487712] Size: 0.404274
2016-04-30 10:43:33.695 FileCopy[6791:487712] Size: 0.419327
2016-04-30 10:43:33.795 FileCopy[6791:487712] Size: 0.438681
2016-04-30 10:43:33.901 FileCopy[6791:487712] Size: 0.458034
2016-04-30 10:43:33.995 FileCopy[6791:487712] Size: 0.475238
2016-04-30 10:43:34.094 FileCopy[6791:487712] Size: 0.490290
2016-04-30 10:43:34.199 FileCopy[6791:487712] Size: 0.509644
2016-04-30 10:43:34.295 FileCopy[6791:487712] Size: 0.528997
2016-04-30 10:43:34.395 FileCopy[6791:487712] Size: 0.541900
2016-04-30 10:43:34.498 FileCopy[6791:487712] Size: 0.556953
2016-04-30 10:43:34.595 FileCopy[6791:487712] Size: 0.574156
2016-04-30 10:43:34.695 FileCopy[6791:487712] Size: 0.595660
2016-04-30 10:43:34.795 FileCopy[6791:487712] Size: 0.610712
2016-04-30 10:43:34.895 FileCopy[6791:487712] Size: 0.627916
2016-04-30 10:43:34.994 FileCopy[6791:487712] Size: 0.647269
2016-04-30 10:43:35.094 FileCopy[6791:487712] Size: 0.666623
2016-04-30 10:43:35.197 FileCopy[6791:487712] Size: 0.681676
2016-04-30 10:43:35.295 FileCopy[6791:487712] Size: 0.696728
2016-04-30 10:43:35.395 FileCopy[6791:487712] Size: 0.716082
2016-04-30 10:43:35.494 FileCopy[6791:487712] Size: 0.735435
2016-04-30 10:43:35.596 FileCopy[6791:487712] Size: 0.750488
2016-04-30 10:43:35.695 FileCopy[6791:487712] Size: 0.767691
2016-04-30 10:43:35.795 FileCopy[6791:487712] Size: 0.784895
2016-04-30 10:43:35.895 FileCopy[6791:487712] Size: 0.804248
2016-04-30 10:43:36.000 FileCopy[6791:487712] Size: 0.819301
2016-04-30 10:43:36.094 FileCopy[6791:487712] Size: 0.834354
2016-04-30 10:43:36.195 FileCopy[6791:487712] Size: 0.849406
2016-04-30 10:43:36.294 FileCopy[6791:487712] Size: 0.870910
2016-04-30 10:43:36.400 FileCopy[6791:487712] Size: 0.885963
2016-04-30 10:43:36.494 FileCopy[6791:487712] Size: 0.901016
2016-04-30 10:43:36.595 FileCopy[6791:487712] Size: 0.918219
2016-04-30 10:43:36.695 FileCopy[6791:487712] Size: 0.939723
2016-04-30 10:43:36.794 FileCopy[6791:487712] Size: 0.954776
2016-04-30 10:43:36.894 FileCopy[6791:487712] Size: 0.971979
2016-04-30 10:43:36.994 FileCopy[6791:487712] Size: 0.987032
[/format]
It looks like I can use these values as the value for the progress indicator.

Below is the cocoa class I’m trying to use .

The full post can be found here: How to show the progress of copying a large file in iOS?

IDCopyUtils.h


#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>

@protocol IDCopyUtilsDelegate;

@interface IDCopyUtils : NSObject

@property (nonatomic, weak) id<IDCopyUtilsDelegate> delegate;

- (void)copyFileAtPath:(NSString *)sourcePath toPath:(NSString *)targetPath;

@end

// 3. Definition of the delegate's interface
@protocol IDCopyUtilsDelegate <NSObject>

- (void)setCopyProgress:(float)progress;
- (void)didFinishedCopyWithError:(NSError *)error;

@end

IDCopyUtils.m


#import "IDCopyUtils.h"

@interface IDCopyUtils()

@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, strong) NSString *sourcePath;
@property (nonatomic, strong) NSString *targetPath;

@end

@implementation IDCopyUtils

- (void)copyFileAtPath:(NSString *)sourcePath toPath:(NSString *)targetPath
{
    self.sourcePath = sourcePath;
    self.targetPath = targetPath;

    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error;

    if ([fileManager fileExistsAtPath:self.targetPath] == YES) {
        [fileManager removeItemAtPath:self.targetPath error:&error];
    }

    self.timer = [NSTimer scheduledTimerWithTimeInterval:0.100
                                     target:self
                                   selector:@selector(checkFileSize)
                                   userInfo:nil
                                    repeats:YES];

    [self performSelector:@selector(startCopy) withObject:nil afterDelay:0.5];

}

- (void)checkFileSize
{
    dispatch_async(dispatch_get_main_queue(), ^{
        NSDictionary *attributesSource = [[NSFileManager defaultManager] attributesOfItemAtPath:self.sourcePath error:NULL]; unsigned long long fileSize = [attributesSource fileSize];

        NSDictionary *attributesTarget = [[NSFileManager defaultManager] attributesOfItemAtPath:self.targetPath error:NULL]; unsigned long long fileSizeTarget = [attributesTarget fileSize];

        double progress = (float)fileSizeTarget / (float)fileSize;

        if (self.delegate && [self.delegate respondsToSelector:@selector(setCopyProgress:)])
        {
            [self.delegate setCopyProgress];
        }

        NSLog(@"Size: %f", progress);
    });
}

- (void)startCopy
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSError *error;

        if ([fileManager fileExistsAtPath:self.targetPath] == YES) {
            [fileManager removeItemAtPath:self.targetPath error:&error];
        }

        if ([fileManager fileExistsAtPath:self.targetPath] == NO) {
            [fileManager copyItemAtPath:self.sourcePath toPath:self.targetPath error:&error];

            [self.timer invalidate];
            self.timer = nil;

            if (self.delegate && [self.delegate respondsToSelector:@selector(didFinishedCopyWithError:)])
            {
                [self.delegate didFinishedCopyWithError:error];
            }
        }
    });
}

@end

You can use it like this (for example):


NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"iso"];
NSString *targetPath = [documentsDirectory stringByAppendingPathComponent:@"test.iso"];

IDCopyUtils *copyUtils = [[IDCopyUtils alloc] init];
copyUtils.delegate = self;
[copyUtils copyFileAtPath:sourcePath toPath:targetPath];

And you will we able to update you progress view and get notified when the file did finidhed copying using the delegate methods.

I would still really like to learn how to make this work in the App Delegate, but here’s my solution for the meantime.

I was able to connect the outlets in the method itself since I don’t really need to control them in the script itself.


- (void)checkFileSize
{
    dispatch_async(dispatch_get_main_queue(), ^{
        NSDictionary *attributesSource = [[NSFileManager defaultManager] attributesOfItemAtPath:self.sourcePath error:NULL]; unsigned long long fileSize = [attributesSource fileSize];
        
        NSDictionary *attributesTarget = [[NSFileManager defaultManager] attributesOfItemAtPath:self.targetPath error:NULL]; unsigned long long fileSizeTarget = [attributesTarget fileSize];
        
        double progress = (float)fileSizeTarget / (float)fileSize;
        
        NSString *fName = self.sourcePath.lastPathComponent;
        if (self.delegate && [self.delegate respondsToSelector:@selector(setCopyProgress:)])
        {
            [self.delegate setCopyProgress];
        }
        
        NSLog(@"Size: %f", progress);
        [_progressBar setDoubleValue:((float)fileSizeTarget / (float)fileSize) * 100];
        [_fileName setStringValue:[NSString stringWithFormat:@"Copying \"%@\"",fName]];
        [_totalBytes setStringValue:[NSString stringWithFormat:@"of %@",[NSByteCountFormatter stringFromByteCount:fileSize countStyle:NSByteCountFormatterCountStyleFile]]];
        // At some point add time left to the status (Time remainig (elapsedTime/data processed) * dataLeft = timeLeft).
        [_status setStringValue:[NSString stringWithFormat:@"%@",[NSByteCountFormatter stringFromByteCount:(double)fileSizeTarget countStyle:NSByteCountFormatterCountStyleFile]]];
        [_icon setImage:[[NSWorkspace sharedWorkspace]iconForFile:self.sourcePath]];

    });
}