• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Progress Indicators Spin vs Bar
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Progress Indicators Spin vs Bar


  • Subject: Re: Progress Indicators Spin vs Bar
  • From: Ken Tozier <email@hidden>
  • Date: Tue, 21 Jun 2011 00:03:42 -0400

Hi James,

I recently finished a file routing app that does a lot of heavy duty operations to files and found that the combination of NSInvocationOperations/NSOperationQueue to be really programmer friendly.

Among the stuff my app does is copy large image files from A to B, creates thumbnails and grayscale versions of them and writes the info to a database and with NSOperationQueues, there is basically no slowdown at all in the user interface. Queues can be stopped at any time so you could give the user that option. Here's a stripped down skeleton of how I'm using NSOperationQueue/NSInvocationOperation which might get you up and running with queues a bit faster. The key is, they are really forgiving and simple to use.

Of particular interest to you might be the delegate idea which allows the file processing method to continuously update and send info to another process which would help with your progress indicator issue

I just did a test with 1258 full sized images and it routed them, created thumbnails, grayscales and extracted a bunch of info in 3 minutes 24 seconds with no effect on user responsiveness of the machine or the app.

Enjoy

// In this example, your delegate in the user interface code, might have a handler defined like so
- (void) handleImageInfo:(id) inMessage
{
	if ([inMessage isKindOfClass: [NSNumber class]])
		// do something with the file count
	else if ([inMessage isKindOfClass: [NSDictionary class]])
		// add data from inMessage to your user interface
}


// Class that monitors and processes files in a drop folder
// For you, it might be a user selected scanning folder
- (id) init
{
	self = [super init];
	if (self)
	{
		queue		= [[NSOperationQueue alloc] init];
		delegate	= nil;
		selector	= nil;
		return self;
	}

	[self release];
	return nil;
}

- (void) setDelegate:(id) inDelegate
		selector:(SEL) inSelector
{
	delegate		= [inDelegate retain];
	selector		= inSelector;
}


- (void) start
{
	[self queueOperation];
}

- (void) stop
{
	[queue setSuspended: YES];
}

- (void) queueOperation
{
	NSInvocationOperation	*operation;

	operation	= [[[NSInvocationOperation alloc]
						initWithTarget: self
						selector:@selector(processDropFolder)
						object: nil]
						autorelease];

	[operation addObserver: self
			forKeyPath: @"isFinished"
			options: NSKeyValueObservingOptionNew
			context: NULL];

	[queue addOperation: operation];
}

- (void) processDropFolder
{
	NSArray		*fileNames	= UtilContentsOfDirectoryAtPath(dropFolder);

	if ((fileNames != nil) && ([fileNames count] > 0))
	{
		NSNumber *fileCount		= [NSNumber numberWithInt: [fileNames count]];

		// send file count off to delegate
		[delegate performSelector: selector withObject: fileCount];

		// we have some photos to process
		NSEnumerator	*e	= [fileNames objectEnumerator];
		NSString		*filePath;
		NSMutableDictionary	*fileInfo;

		NSLog(@"Scanning: %@", dropFolder);

		while (fileName = [e nextObject])
		{
			// ignore invisible files
			if (![fileName hasPrefix: @"."])
			{
				filePath		= [dropFolder stringByAppendingPathComponent: fileName];

				// read the exif info, find (or create) a thumbnail
				// package it up in a nice NSDictionary and send it
				// to your delegate
				NSDictionary *imgInfo	= UtilImageInfo(filePath);

				if (imgInfo != nil)
					[delegate performSelector: selector withObject: imgInfo];
			}
		}
	}
}

- (void)observeValueForKeyPath:(NSString *) inKeyPath
		ofObject:(id) inObject
		change:(NSDictionary *) inChange
		context:(void *) inContext
{
	if ([inKeyPath isEqualToString: @"isFinished"])
	{
		// remove invocation observer
		[inObject removeObserver: self forKeyPath: @"isFinished"];

		// queue up another pass
		[self queueOperation];
	}
}

// utility function that reads info from an image file
NSMutableDictionary *UtilImageInfo(NSString *inPath)
{
	NSWorkspace			*workspace	= [NSWorkspace sharedWorkspace];
	NSError				*error		= nil;
	NSString			*type		= [workspace typeOfFile: inPath error: &error];

	if ((error == nil) && [workspace type: type conformsToType: (NSString *) kUTTypeImage])
	{
		// inPath is some sort of image
		NSURL				*url	= [NSURL fileURLWithPath: inPath];
		CGImageSourceRef	imgSrc	= CGImageSourceCreateWithURL((CFURLRef) url, NULL);

		if (imgSrc != nil)
		{
			NSDictionary	*props	= (NSDictionary *) CGImageSourceCopyPropertiesAtIndex(imgSrc,0, NULL);
			NSMutableDictionary	*result	= [NSMutableDictionary dictionary];

			// copy out whatever info you're interested from props
			NSNumber	*zero			= [NSNumber numberWithInt: 0];
			NSString	*colorModel		= [props objectForKey: @"ColorModel"],
						*colorProfile	= [props objectForKey: @"ProfileName"],
						*pixelWidth		= [props objectForKey: @"PixelWidth"],
						*pixelHeight	= [props objectForKey: @"PixelHeight"],
						*bitsPerPixel	= [props objectForKey: @"Depth"];

			[result setObject: ((colorModel == nil) ? @"" : colorModel) forKey: @"color"];
			[result setObject: ((colorProfile == nil) ? @"" : colorProfile) forKey: @"profile"];
			[result setObject: ((pixelWidth == nil) ? zero : [NSNumber numberWithFloat:[pixelWidth floatValue]]) forKey: @"width"];
			[result setObject: ((pixelHeight == nil) ? zero : [NSNumber numberWithFloat:[pixelHeight floatValue]]) forKey: @"height"];
			[result setObject: ((bitsPerPixel == nil) ? zero : [NSNumber numberWithFloat:[bitsPerPixel floatValue]]) forKey: @"bits_per_pixel"];

			CFRelease(imgSrc);
			[props release];

			return result;
		}
	}

	return nil;
}


_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

References: 
 >Progress Indicators Spin vs Bar (From: James Merkel <email@hidden>)
 >Re: Progress Indicators Spin vs Bar (From: Quincey Morris <email@hidden>)
 >Re: Progress Indicators Spin vs Bar (From: James Merkel <email@hidden>)
 >Re: Progress Indicators Spin vs Bar (From: James Merkel <email@hidden>)
 >Re: Progress Indicators Spin vs Bar (From: Kyle Sluder <email@hidden>)
 >Re: Progress Indicators Spin vs Bar (From: James Merkel <email@hidden>)
 >Re: Progress Indicators Spin vs Bar (From: Mike Abdullah <email@hidden>)
 >Re: Progress Indicators Spin vs Bar (From: James Merkel <email@hidden>)
 >Re: Progress Indicators Spin vs Bar (From: Greg Parker <email@hidden>)
 >Re: Progress Indicators Spin vs Bar (From: James Merkel <email@hidden>)
 >Re: Progress Indicators Spin vs Bar (From: Conrad Shultz <email@hidden>)
 >Re: Progress Indicators Spin vs Bar (From: James Merkel <email@hidden>)

  • Prev by Date: Re: Progress Indicators Spin vs Bar
  • Next by Date: Re: Disable implicit animations in layer backed NSScrollViews?
  • Previous by thread: Re: Progress Indicators Spin vs Bar
  • Next by thread: Re: Progress Indicators Spin vs Bar
  • Index(es):
    • Date
    • Thread