Skip to content
Browse files

[CHANGE] Use NSOperation and NSOperationQueue to multithread the load…

…ing of images
  • Loading branch information...
1 parent b0863e1 commit baf1fe71abadd9b2b12eae4f5b481c37a25009ee @mattball committed Mar 28, 2009
View
22 MBCoverFlowImageLoadOperation.h
@@ -0,0 +1,22 @@
+//
+// MBCoverFlowImageLoadOperation.h
+// MBCoverFlowView
+//
+// Created by Matt Ball on 3/28/09.
+// Copyright 2009 Daybreak Apps. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#import <QuartzCore/QuartzCore.h>
+
+@interface MBCoverFlowImageLoadOperation : NSOperation {
+ CALayer *_layer;
+ NSString *_imageKeyPath;
+}
+
+@property (nonatomic, retain) CALayer *layer;
+@property (nonatomic, copy) NSString *imageKeyPath;
+
+- (id)initWithLayer:(CALayer *)layer imageKeyPath:(NSString *)imageKeyPath;
+
+@end
View
64 MBCoverFlowImageLoadOperation.m
@@ -0,0 +1,64 @@
+//
+// MBCoverFlowImageLoadOperation.m
+// MBCoverFlowView
+//
+// Created by Matt Ball on 3/28/09.
+// Copyright 2009 Daybreak Apps. All rights reserved.
+//
+
+#import "MBCoverFlowImageLoadOperation.h"
+
+#import "NSImage+MBCoverFlowAdditions.h"
+
+@implementation MBCoverFlowImageLoadOperation
+
+@synthesize layer=_layer, imageKeyPath=_imageKeyPath;
+
+- (id)initWithLayer:(CALayer *)layer imageKeyPath:(NSString *)imageKeyPath;
+{
+ if (self = [super init]) {
+ _layer = [layer retain];
+ _imageKeyPath = [imageKeyPath copy];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ self.layer = nil;
+ self.imageKeyPath = nil;
+ [super dealloc];
+}
+
+- (BOOL)isConcurrent
+{
+ return NO;
+}
+
+- (void)main
+{
+ @try {
+ NSImage *image;
+ NSObject *object = [self.layer valueForKey:@"representedObject"];
+
+ if (self.imageKeyPath != nil) {
+ image = [object valueForKeyPath:self.imageKeyPath];
+ } else if ([object isKindOfClass:[NSImage class]]) {
+ image = (NSImage *)object;
+ }
+
+ CGImageRef imageRef = [image imageRef];
+
+ CALayer *imageLayer = [[self.layer sublayers] objectAtIndex:0];
+ CALayer *reflectionLayer = [[imageLayer sublayers] objectAtIndex:0];
+
+ imageLayer.contents = (id)imageRef;
+ reflectionLayer.contents = (id)imageRef;
+ imageLayer.backgroundColor = NULL;
+ reflectionLayer.backgroundColor = NULL;
+ } @catch (NSException *e) {
+ // If the key path isn't valid, do nothing
+ }
+}
+
+@end
View
1 MBCoverFlowScroller.m
@@ -153,6 +153,7 @@ - (void)setNumberOfIncrements:(NSUInteger)newIncrements
} else {
[self setKnobProportion:1.0];
}
+ [self setNeedsDisplay:YES];
}
/* The documentation for NSScroller says to use -drawArrow:highlight:, but
View
2 MBCoverFlowView.h
@@ -53,6 +53,8 @@
BOOL _autoresizesItems;
NSString *_imageKeyPath;
+
+ NSOperationQueue *_imageLoadQueue;
}
/**
View
58 MBCoverFlowView.m
@@ -26,6 +26,7 @@ of this software and associated documentation files (the "Software"), to deal
#import "MBCoverFlowView.h"
+#import "MBCoverFlowImageLoadOperation.h"
#import "MBCoverFlowScroller.h"
#import "NSImage+MBCoverFlowAdditions.h"
@@ -62,7 +63,7 @@ @interface MBCoverFlowView ()
- (float)_positionOfSelectedItem;
- (CALayer *)_newLayer;
- (void)_scrollerChange:(MBCoverFlowScroller *)scroller;
-- (void)_refreshLayers;
+- (void)_refreshLayer:(CALayer *)layer;
- (CALayer *)_layerForObject:(id)object;
@end
@@ -79,6 +80,9 @@ @implementation MBCoverFlowView
- (id)initWithFrame:(NSRect)frameRect
{
if (self = [super initWithFrame:frameRect]) {
+ _imageLoadQueue = [[NSOperationQueue alloc] init];
+ [_imageLoadQueue setMaxConcurrentOperationCount:1];
+
_autoresizesItems = YES;
[self setAutoresizesSubviews:YES];
@@ -240,6 +244,8 @@ - (void)dealloc
self.content = nil;
self.imageKeyPath = nil;
CGImageRelease(_shadowImage);
+ [_imageLoadQueue release];
+ _imageLoadQueue = nil;
[super dealloc];
}
@@ -343,6 +349,10 @@ - (void)resizeSubviewsWithOldSize:(NSSize)oldSize
- (void)setContent:(NSArray *)newContents
{
+ if ([newContents isEqualToArray:self.content]) {
+ return;
+ }
+
NSArray *oldContent = [self.content retain];
if (_content) {
@@ -361,6 +371,7 @@ - (void)setContent:(NSArray *)newContents
for (NSObject *object in itemsToAdd) {
CALayer *layer = [self _newLayer];
[layer setValue:object forKey:@"representedObject"];
+ [self _refreshLayer:layer];
}
// Remove any items which are no longer present
@@ -373,9 +384,6 @@ - (void)setContent:(NSArray *)newContents
[oldContent release];
- // Update the images and indexes
- [self _refreshLayers];
-
[_scroller setNumberOfIncrements:([self.content count]-1)];
self.selectionIndex = self.selectionIndex;
}
@@ -624,37 +632,17 @@ - (void)_scrollerChange:(MBCoverFlowScroller *)sender
}
}
-- (void)_refreshLayers
-{
- for (CALayer *layer in [_scrollLayer sublayers]) {
- CALayer *imageLayer = [[layer sublayers] objectAtIndex:0];
- CALayer *reflectionLayer = [[imageLayer sublayers] objectAtIndex:0];
-
- NSObject *object = [layer valueForKey:@"representedObject"];
- NSInteger index = [self.content indexOfObject:object];
-
- [layer setValue:[NSNumber numberWithInteger:index] forKey:@"index"];
-
- @try {
- NSImage *image;
-
- if (self.imageKeyPath != nil) {
- image = [object valueForKeyPath:self.imageKeyPath];
- } else if ([object isKindOfClass:[NSImage class]]) {
- image = (NSImage *)object;
- }
-
- CGImageRef imageRef = [image imageRef];
-
- imageLayer.contents = (id)imageRef;
- reflectionLayer.contents = (id)imageRef;
- imageLayer.backgroundColor = NULL;
- reflectionLayer.backgroundColor = NULL;
- } @catch (NSException *e) {
- // If the key path isn't valid, move to the next item
- continue;
- }
- }
+- (void)_refreshLayer:(CALayer *)layer
+{
+ NSObject *object = [layer valueForKey:@"representedObject"];
+ NSInteger index = [self.content indexOfObject:object];
+
+ [layer setValue:[NSNumber numberWithInteger:index] forKey:@"index"];
+
+ // Create the operation
+ NSOperation *operation = [[MBCoverFlowImageLoadOperation alloc] initWithLayer:layer imageKeyPath:self.imageKeyPath];
+ [_imageLoadQueue addOperation:operation];
+ [operation release];
}
- (CALayer *)_layerForObject:(id)object
View
6 MBCoverFlowView.xcodeproj/project.pbxproj
@@ -12,6 +12,7 @@
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
C91E73FC0F79F75C00FD319E /* MBCoverFlowScroller.m in Sources */ = {isa = PBXBuildFile; fileRef = C91E73FB0F79F75C00FD319E /* MBCoverFlowScroller.m */; };
+ C91E7EE70F7F442F00FD319E /* MBCoverFlowImageLoadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C91E7EE60F7F442F00FD319E /* MBCoverFlowImageLoadOperation.m */; };
C9D1735A0F6B38CD0097827F /* MBCoverFlowView.m in Sources */ = {isa = PBXBuildFile; fileRef = C9D173590F6B38CD0097827F /* MBCoverFlowView.m */; };
C9D1737A0F6B3ADC0097827F /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9D173790F6B3ADC0097827F /* QuartzCore.framework */; };
C9D178230F6F97D60097827F /* MBCoverFlowViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C9D178220F6F97D60097827F /* MBCoverFlowViewController.m */; };
@@ -31,6 +32,8 @@
8D1107320486CEB800E47090 /* MBCoverFlowView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MBCoverFlowView.app; sourceTree = BUILT_PRODUCTS_DIR; };
C91E73FA0F79F75C00FD319E /* MBCoverFlowScroller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBCoverFlowScroller.h; sourceTree = "<group>"; };
C91E73FB0F79F75C00FD319E /* MBCoverFlowScroller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBCoverFlowScroller.m; sourceTree = "<group>"; };
+ C91E7EE50F7F442F00FD319E /* MBCoverFlowImageLoadOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBCoverFlowImageLoadOperation.h; sourceTree = "<group>"; };
+ C91E7EE60F7F442F00FD319E /* MBCoverFlowImageLoadOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBCoverFlowImageLoadOperation.m; sourceTree = "<group>"; };
C9D173580F6B38CD0097827F /* MBCoverFlowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBCoverFlowView.h; sourceTree = "<group>"; };
C9D173590F6B38CD0097827F /* MBCoverFlowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBCoverFlowView.m; sourceTree = "<group>"; };
C9D173790F6B3ADC0097827F /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = "<absolute>"; };
@@ -64,6 +67,8 @@
C9E9ACB50F78B188004DDC0A /* NSImage+MBCoverFlowAdditions.m */,
C91E73FA0F79F75C00FD319E /* MBCoverFlowScroller.h */,
C91E73FB0F79F75C00FD319E /* MBCoverFlowScroller.m */,
+ C91E7EE50F7F442F00FD319E /* MBCoverFlowImageLoadOperation.h */,
+ C91E7EE60F7F442F00FD319E /* MBCoverFlowImageLoadOperation.m */,
);
name = Classes;
sourceTree = "<group>";
@@ -195,6 +200,7 @@
C9D178230F6F97D60097827F /* MBCoverFlowViewController.m in Sources */,
C9E9ACB60F78B188004DDC0A /* NSImage+MBCoverFlowAdditions.m in Sources */,
C91E73FC0F79F75C00FD319E /* MBCoverFlowScroller.m in Sources */,
+ C91E7EE70F7F442F00FD319E /* MBCoverFlowImageLoadOperation.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
10 MBCoverFlowViewController.m
@@ -51,9 +51,7 @@ - (void)awakeFromNib
items = [images copy];
-// [(MBCoverFlowView *)self.view setContent:images];
-
-/* NSViewController *labelViewController = [[NSViewController alloc] initWithNibName:nil bundle:nil];
+ NSViewController *labelViewController = [[NSViewController alloc] initWithNibName:nil bundle:nil];
NSTextField *label = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 10, 10)];
[label setBordered:NO];
[label setBezeled:NO];
@@ -67,7 +65,7 @@ - (void)awakeFromNib
[labelViewController setView:label];
[label release];
[(MBCoverFlowView *)self.view setAccessoryController:labelViewController];
- [labelViewController release];*/
+ [labelViewController release];
[(MBCoverFlowView *)self.view setShowsScrollbar:YES];
}
@@ -80,6 +78,10 @@ - (void)dealloc
- (void)addItem:(id)sender
{
+ if ([items isEqualToArray:[(MBCoverFlowView *)self.view content]]) {
+ return;
+ }
+
NSArray *content = [items subarrayWithRange:NSMakeRange(0, [[(MBCoverFlowView *)self.view content] count]+1)];
[(MBCoverFlowView *)self.view setContent:content];
}

0 comments on commit baf1fe7

Please sign in to comment.
Something went wrong with that request. Please try again.