diff --git a/OGImage/OGImage.h b/OGImage/OGImage.h index e3456d7..aca2077 100644 --- a/OGImage/OGImage.h +++ b/OGImage/OGImage.h @@ -25,17 +25,17 @@ /** * Convenience method: This is equivalent to calling - * [ogimg addObserver:observer forKeyPath:@"image" options:NSKeyValueObservingOptionNew context:nil]; - * [ogimg addObserver:observer forKeyPath:@"error" options:NSKeyValueObservingOptionNew context:nil]; + * [ogimg addObserver:observer forKeyPath:@"image" options:NSKeyValueObservingOptionNew context:context]; + * [ogimg addObserver:observer forKeyPath:@"error" options:NSKeyValueObservingOptionNew context:context]; */ -- (void)addObserver:(NSObject *)observer; +- (void)addObserver:(NSObject *)observer context:(void *)context; /** * Convenience method: This is equivalent to calling - * [ogimg removeObserver:observer forKeyPath:@"image"]; - * [ogimg removeObserver:observer forKeyPath:@"error"]; + * [ogimg removeObserver:observer forKeyPath:@"image" context:context]; + * [ogimg removeObserver:observer forKeyPath:@"error" context:context]; */ -- (void)removeObserver:(NSObject *)observer; +- (void)removeObserver:(NSObject *)observer context:(void *)context; /** * Subclasses can override this method to perform caching, processing, etc., but diff --git a/OGImage/OGImage.m b/OGImage/OGImage.m index 43c14aa..cd8ce29 100644 --- a/OGImage/OGImage.m +++ b/OGImage/OGImage.m @@ -26,17 +26,17 @@ - (id)initWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImage { return self; } -- (void)addObserver:(NSObject *)observer { - [self addObserver:observer forKeyPath:@"image" options:NSKeyValueObservingOptionNew context:nil]; - [self addObserver:observer forKeyPath:@"error" options:NSKeyValueObservingOptionNew context:nil]; +- (void)addObserver:(NSObject *)observer context:(void *)context { + [self addObserver:observer forKeyPath:@"image" options:NSKeyValueObservingOptionNew context:context]; + [self addObserver:observer forKeyPath:@"error" options:NSKeyValueObservingOptionNew context:context]; } -- (void)removeObserver:(NSObject *)observer { +- (void)removeObserver:(NSObject *)observer context:(void *)context { @try { - [self removeObserver:observer forKeyPath:@"image"]; + [self removeObserver:observer forKeyPath:@"image" context:context]; } @catch (NSException *e) {} @try { - [self removeObserver:observer forKeyPath:@"error"]; + [self removeObserver:observer forKeyPath:@"error" context:context]; } @catch (NSException *e) {} } diff --git a/OGImage/OGScaledImage.h b/OGImage/OGScaledImage.h index 5bcba27..7bd23a6 100644 --- a/OGImage/OGScaledImage.h +++ b/OGImage/OGScaledImage.h @@ -49,11 +49,11 @@ /** * Equivalent to adding an observer for @"image", @"scaledImage", & @"error" */ -- (void)addObserver:(NSObject *)observer; +- (void)addObserver:(NSObject *)observer context:(void *)context; /** * Equivalent to removing an observer for @"image", @"scaledImage", & @"error" */ -- (void)removeObserver:(NSObject *)observer; +- (void)removeObserver:(NSObject *)observer context:(void *)context; /** * The scaled imageā€”The inherited `image` property is set to the full-size image at `url`. diff --git a/OGImage/OGScaledImage.m b/OGImage/OGScaledImage.m index ca63879..9424332 100644 --- a/OGImage/OGScaledImage.m +++ b/OGImage/OGScaledImage.m @@ -73,14 +73,14 @@ - (id)initWithImage:(__OGImage *)image size:(CGSize)size cornerRadius:(CGFloat)c return self; } -- (void)addObserver:(NSObject *)observer { - [super addObserver:observer]; - [self addObserver:observer forKeyPath:@"scaledImage" options:NSKeyValueObservingOptionNew context:nil]; +- (void)addObserver:(NSObject *)observer context:(void *)context { + [super addObserver:observer context:context]; + [self addObserver:observer forKeyPath:@"scaledImage" options:NSKeyValueObservingOptionNew context:context]; } -- (void)removeObserver:(NSObject *)observer { - [super removeObserver:observer]; - [self removeObserver:observer forKeyPath:@"scaledImage"]; +- (void)removeObserver:(NSObject *)observer context:(void *)context { + [super removeObserver:observer context:context]; + [self removeObserver:observer forKeyPath:@"scaledImage" context:context]; } - (void)loadImageFromURL { diff --git a/OGImageDemo/OGImageDemo/OGImageTableViewCell.m b/OGImageDemo/OGImageDemo/OGImageTableViewCell.m index d08ff55..371c701 100644 --- a/OGImageDemo/OGImageDemo/OGImageTableViewCell.m +++ b/OGImageDemo/OGImageDemo/OGImageTableViewCell.m @@ -9,6 +9,8 @@ #import "OGImageTableViewCell.h" #import "OGScaledImage.h" +static NSString *KVOContext = @"OGImageTableViewCell observation"; + @implementation OGImageTableViewCell - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { @@ -25,13 +27,18 @@ - (void)setSelected:(BOOL)selected animated:(BOOL)animated { #pragma mark - KVO - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - NSAssert(YES == [NSThread isMainThread], @"KVO fired on thread other than main..."); - if ([keyPath isEqualToString:@"scaledImage"]) { - self.imageView.image = self.image.scaledImage; - self.textLabel.text = [[self.image.url path] lastPathComponent]; - self.detailTextLabel.text = [NSString stringWithFormat:@"%.2f", self.image.loadTime]; - } else if ([keyPath isEqualToString:@"error"]) { - + if( (void *)&KVOContext == context ) { + NSAssert(YES == [NSThread isMainThread], @"KVO fired on thread other than main..."); + if ([keyPath isEqualToString:@"scaledImage"]) { + self.imageView.image = self.image.scaledImage; + self.textLabel.text = [[self.image.url path] lastPathComponent]; + self.detailTextLabel.text = [NSString stringWithFormat:@"%.2f", self.image.loadTime]; + } else if ([keyPath isEqualToString:@"error"]) { + + } + } + else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } @@ -42,19 +49,19 @@ - (void)setImage:(OGScaledImage *)image { * When the cell's image is set, we want to first make sure we're no longer listening * for any KVO notifications on the cell's previous image. */ - [_image removeObserver:self forKeyPath:@"error"]; - [_image removeObserver:self forKeyPath:@"scaledImage"]; + [_image removeObserver:self forKeyPath:@"error" context:&KVOContext]; + [_image removeObserver:self forKeyPath:@"scaledImage" context:&KVOContext]; _image = image; self.imageView.image = _image.scaledImage; self.textLabel.text = [[self.image.url path] lastPathComponent]; self.detailTextLabel.text = NSLocalizedString(@"Loading", @""); - [_image addObserver:self forKeyPath:@"error" options:NSKeyValueObservingOptionNew context:nil]; - [_image addObserver:self forKeyPath:@"scaledImage" options:NSKeyValueObservingOptionNew context:nil]; + [_image addObserver:self forKeyPath:@"error" options:NSKeyValueObservingOptionNew context:&KVOContext]; + [_image addObserver:self forKeyPath:@"scaledImage" options:NSKeyValueObservingOptionNew context:&KVOContext]; } - (void)dealloc { - [_image removeObserver:self forKeyPath:@"error"]; - [_image removeObserver:self forKeyPath:@"scaledImage"]; + [_image removeObserver:self forKeyPath:@"error" context:&KVOContext]; + [_image removeObserver:self forKeyPath:@"scaledImage" context:&KVOContext]; } @end diff --git a/OGImageDemo/OGImageTests/OGImageAssetsLibraryTests.m b/OGImageDemo/OGImageTests/OGImageAssetsLibraryTests.m index 8d61b8f..0a71a11 100644 --- a/OGImageDemo/OGImageTests/OGImageAssetsLibraryTests.m +++ b/OGImageDemo/OGImageTests/OGImageAssetsLibraryTests.m @@ -12,6 +12,8 @@ #import +static NSString *KVOContext = @"OGImageAssetsLibraryTests observation"; + static CGSize const OGExpectedSize = {1024.f, 768.f}; @interface OGImageAssetsLibraryTests : GHAsyncTestCase @@ -44,18 +46,23 @@ - (void)setUp { } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - if ([keyPath isEqualToString:@"image"]) { - OGCachedImage *image = (OGCachedImage *)object; - if (nil != image.image) { - GHAssertTrue(CGSizeEqualToSize(OGExpectedSize, image.image.size), @"Expected image of size %@, got %@", NSStringFromCGSize(OGExpectedSize), NSStringFromCGSize(image.image.size)); - [self notify:kGHUnitWaitStatusSuccess]; - } else { + if ((void *)&KVOContext == context) { + if ([keyPath isEqualToString:@"image"]) { + OGCachedImage *image = (OGCachedImage *)object; + if (nil != image.image) { + GHAssertTrue(CGSizeEqualToSize(OGExpectedSize, image.image.size), @"Expected image of size %@, got %@", NSStringFromCGSize(OGExpectedSize), NSStringFromCGSize(image.image.size)); + [self notify:kGHUnitWaitStatusSuccess]; + } else { + [self notify:kGHUnitWaitStatusFailure]; + } + } else if ([keyPath isEqualToString:@"error"]) { + OGCachedImage *image = (OGCachedImage *)object; + GHFail(@"Got error loading OGCachedImage: %@", image.error); [self notify:kGHUnitWaitStatusFailure]; } - } else if ([keyPath isEqualToString:@"error"]) { - OGCachedImage *image = (OGCachedImage *)object; - GHFail(@"Got error loading OGCachedImage: %@", image.error); - [self notify:kGHUnitWaitStatusFailure]; + } + else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } @@ -63,9 +70,9 @@ - (void)testAssetsLibrary { [self prepare]; GHAssertNotNil(_assetURL, @"Expect _assetURL to be populated by setUp"); OGCachedImage *image = [[OGCachedImage alloc] initWithURL:_assetURL key:nil]; - [image addObserver:self]; + [image addObserver:self context:&KVOContext]; [self waitForStatus:kGHUnitWaitStatusSuccess timeout:10.]; - [image removeObserver:self]; + [image removeObserver:self context:&KVOContext]; } @end \ No newline at end of file diff --git a/OGImageDemo/OGImageTests/OGImageAsyncTests.m b/OGImageDemo/OGImageTests/OGImageAsyncTests.m index 302ab0c..3d64c9e 100644 --- a/OGImageDemo/OGImageTests/OGImageAsyncTests.m +++ b/OGImageDemo/OGImageTests/OGImageAsyncTests.m @@ -10,6 +10,8 @@ #import "OGImage.h" #import "OGImageLoader.h" +static NSString *KVOContext = @"OGImageAsyncTests observation"; + static NSString * const TEST_IMAGE_URL_STRING = @"http://easyquestion.net/thinkagain/wp-content/uploads/2009/05/james-bond.jpg"; static NSString * const FAKE_IMAGE_URL_STRING = @"http://easyquestion.net/thinkagain/wp-content/uploads/2009/05/james00.jpg"; static const CGSize TEST_IMAGE_SIZE = {317.f, 400.f}; @@ -22,26 +24,31 @@ @interface OGImage404Test : GHAsyncTestCase @implementation OGImage404Test - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - NSAssert(YES == [NSThread isMainThread], @"Expected `observeValueForKeyPath` to only be called on main thread"); - if ([keyPath isEqualToString:@"error"]) { - OGImage *image = (OGImage *)object; - GHTestLog(@"Error changed: %@", image.error); - if (OGImageLoadingError == image.error.code) { - // we expect a loading error here - [self notify:kGHUnitWaitStatusSuccess]; - } else { - [self notify:kGHUnitWaitStatusFailure]; + if ((void *)&KVOContext == context) { + NSAssert(YES == [NSThread isMainThread], @"Expected `observeValueForKeyPath` to only be called on main thread"); + if ([keyPath isEqualToString:@"error"]) { + OGImage *image = (OGImage *)object; + GHTestLog(@"Error changed: %@", image.error); + if (OGImageLoadingError == image.error.code) { + // we expect a loading error here + [self notify:kGHUnitWaitStatusSuccess]; + } else { + [self notify:kGHUnitWaitStatusFailure]; + } + return; } - return; + } + else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } - (void)test404 { [self prepare]; OGImage *image = [[OGImage alloc] initWithURL:[NSURL URLWithString:FAKE_IMAGE_URL_STRING]]; - [image addObserver:self]; + [image addObserver:self context:&KVOContext]; [self waitForStatus:kGHUnitWaitStatusSuccess timeout:10.]; - [image removeObserver:self]; + [image removeObserver:self context:&KVOContext]; } @end @@ -54,27 +61,32 @@ @interface OGImageTest1 : GHAsyncTestCase @implementation OGImageTest1 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - NSAssert(YES == [NSThread isMainThread], @"Expected `observeValueForKeyPath` to only be called on main thread"); - if ([keyPath isEqualToString:@"image"]) { - OGImage *image = (OGImage *)object; - GHTestLog(@"Image loaded: %@ : %@", image.image, NSStringFromCGSize(image.image.size)); - if (NO == CGSizeEqualToSize(image.image.size, TEST_IMAGE_SIZE)) { - [self notify:kGHUnitWaitStatusFailure]; - } else { - [self notify:kGHUnitWaitStatusSuccess]; + if ((void *)&KVOContext == context) { + NSAssert(YES == [NSThread isMainThread], @"Expected `observeValueForKeyPath` to only be called on main thread"); + if ([keyPath isEqualToString:@"image"]) { + OGImage *image = (OGImage *)object; + GHTestLog(@"Image loaded: %@ : %@", image.image, NSStringFromCGSize(image.image.size)); + if (NO == CGSizeEqualToSize(image.image.size, TEST_IMAGE_SIZE)) { + [self notify:kGHUnitWaitStatusFailure]; + } else { + [self notify:kGHUnitWaitStatusSuccess]; + } + return; } - return; + GHTestLog(@"Unexpected key change..."); + [self notify:kGHUnitWaitStatusFailure]; + } + else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } - GHTestLog(@"Unexpected key change..."); - [self notify:kGHUnitWaitStatusFailure]; } - (void)testImageOne { [self prepare]; OGImage *image = [[OGImage alloc] initWithURL:[NSURL URLWithString:TEST_IMAGE_URL_STRING]]; - [image addObserver:self forKeyPath:@"image" options:NSKeyValueObservingOptionNew context:nil]; + [image addObserver:self forKeyPath:@"image" options:NSKeyValueObservingOptionNew context:&KVOContext]; [self waitForStatus:kGHUnitWaitStatusSuccess timeout:10.]; - [image removeObserver:self forKeyPath:@"image"]; + [image removeObserver:self forKeyPath:@"image" context:&KVOContext]; } @end diff --git a/OGImageDemo/OGImageTests/OGImageFileTests.m b/OGImageDemo/OGImageTests/OGImageFileTests.m index 1ba5e30..32a6e64 100644 --- a/OGImageDemo/OGImageTests/OGImageFileTests.m +++ b/OGImageDemo/OGImageTests/OGImageFileTests.m @@ -10,6 +10,8 @@ #import "OGCachedImage.h" #import "OGImageCache.h" +static NSString *KVOContext = @"OGImageFileTests observation"; + static CGSize const OGExpectedSize = {1024.f, 768.f}; @interface OGImageFileTests : GHAsyncTestCase @@ -23,16 +25,21 @@ - (void)setUp { } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - if ([keyPath isEqualToString:@"image"]) { - OGCachedImage *image = (OGCachedImage *)object; - if (nil == image) { + if ((void *)&KVOContext == context) { + if ([keyPath isEqualToString:@"image"]) { + OGCachedImage *image = (OGCachedImage *)object; + if (nil == image) { + [self notify:kGHUnitWaitStatusFailure]; + } else { + GHAssertTrue(CGSizeEqualToSize(OGExpectedSize, image.image.size), @"Expected image of size %@, got %@", NSStringFromCGSize(OGExpectedSize), NSStringFromCGSize(image.image.size)); + [self notify:kGHUnitWaitStatusSuccess]; + } + } else if ([keyPath isEqualToString:@"error"]) { [self notify:kGHUnitWaitStatusFailure]; - } else { - GHAssertTrue(CGSizeEqualToSize(OGExpectedSize, image.image.size), @"Expected image of size %@, got %@", NSStringFromCGSize(OGExpectedSize), NSStringFromCGSize(image.image.size)); - [self notify:kGHUnitWaitStatusSuccess]; } - } else if ([keyPath isEqualToString:@"error"]) { - [self notify:kGHUnitWaitStatusFailure]; + } + else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } @@ -41,9 +48,9 @@ - (void)testFileURL { NSURL *imageURL = [[NSBundle mainBundle] URLForResource:@"Origami" withExtension:@"jpg"]; GHAssertNotNil(imageURL, @"Couldn't get URL for test image"); OGCachedImage *image = [[OGCachedImage alloc] initWithURL:imageURL key:nil]; - [image addObserver:self]; + [image addObserver:self context:&KVOContext]; [self waitForStatus:kGHUnitWaitStatusSuccess timeout:10.]; - [image removeObserver:self]; + [image removeObserver:self context:&KVOContext]; } @end diff --git a/OGImageDemo/OGImageTests/OGImageIdempotentTests.m b/OGImageDemo/OGImageTests/OGImageIdempotentTests.m index ea3c179..2ffe697 100644 --- a/OGImageDemo/OGImageTests/OGImageIdempotentTests.m +++ b/OGImageDemo/OGImageTests/OGImageIdempotentTests.m @@ -9,6 +9,8 @@ #import "GHAsyncTestCase.h" #import "OGImage.h" +static NSString *KVOContext = @"OGImageIdempotentTests observation"; + static NSString * const TEST_IMAGE_URL_STRING = @"http://easyquestion.net/thinkagain/wp-content/uploads/2009/05/james-bond.jpg"; @interface OGImageIdempotentTests : GHAsyncTestCase { @@ -23,13 +25,18 @@ @interface OGImageIdempotentTests : GHAsyncTestCase { @implementation OGImageIdempotentTests - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - if (_image1 == object) { - _image1Loaded = YES; - } else if (_image2 == object) { - _image2Loaded = YES; + if ((void *)&KVOContext == context) { + if (_image1 == object) { + _image1Loaded = YES; + } else if (_image2 == object) { + _image2Loaded = YES; + } + if (_image1Loaded && _image2Loaded) { + [self notify:kGHUnitWaitStatusSuccess]; + } } - if (_image1Loaded && _image2Loaded) { - [self notify:kGHUnitWaitStatusSuccess]; + else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } @@ -38,11 +45,11 @@ - (void)testIdempotent { // a single network request with notifications [self prepare]; _image1 = [[OGImage alloc] initWithURL:[NSURL URLWithString:TEST_IMAGE_URL_STRING]]; - [_image1 addObserver:self]; + [_image1 addObserver:self context:&KVOContext]; _image2 = [[OGImage alloc] initWithURL:[NSURL URLWithString:TEST_IMAGE_URL_STRING]]; - [_image2 addObserver:self]; + [_image2 addObserver:self context:&KVOContext]; [self waitForStatus:kGHUnitWaitStatusSuccess timeout:15.f]; - [_image1 removeObserver:self]; - [_image2 removeObserver:self]; + [_image1 removeObserver:self context:&KVOContext]; + [_image2 removeObserver:self context:&KVOContext]; } @end diff --git a/OGImageDemo/OGImageTests/OGImageProcessingTests.m b/OGImageDemo/OGImageTests/OGImageProcessingTests.m index 48c09f3..fa982e0 100644 --- a/OGImageDemo/OGImageTests/OGImageProcessingTests.m +++ b/OGImageDemo/OGImageTests/OGImageProcessingTests.m @@ -11,6 +11,8 @@ #import "OGScaledImage.h" #import "OGImageCache.h" +static NSString *KVOContext = @"OGImageProcessingTests observation"; + extern CGSize OGAspectFit(CGSize from, CGSize to); extern CGSize OGAspectFill(CGSize from, CGSize to, CGPoint *offset); @@ -81,29 +83,34 @@ - (void)tearDown { } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - NSAssert(YES == [NSThread isMainThread], @"Expected `observeValueForKeyPath` to only be called on main thread"); - if ([keyPath isEqualToString:@"scaledImage"]) { - OGScaledImage *image = (OGScaledImage *)object; - GHTestLog(@"Image loaded: %@ : %@", image.image, NSStringFromCGSize(image.image.size)); - CGSize retinaSize = TEST_SCALE_SIZE; - retinaSize.width *= [UIScreen mainScreen].scale; - retinaSize.height *= [UIScreen mainScreen].scale; - CGSize expectedSize = OGAspectFit(TEST_IMAGE_SIZE, TEST_SCALE_SIZE); - if (NO == CGSizeEqualToSize(image.scaledImage.size, expectedSize)) { - [self notify:kGHUnitWaitStatusFailure]; - } else { - [self notify:kGHUnitWaitStatusSuccess]; + if ((void *)&KVOContext == context) { + NSAssert(YES == [NSThread isMainThread], @"Expected `observeValueForKeyPath` to only be called on main thread"); + if ([keyPath isEqualToString:@"scaledImage"]) { + OGScaledImage *image = (OGScaledImage *)object; + GHTestLog(@"Image loaded: %@ : %@", image.image, NSStringFromCGSize(image.image.size)); + CGSize retinaSize = TEST_SCALE_SIZE; + retinaSize.width *= [UIScreen mainScreen].scale; + retinaSize.height *= [UIScreen mainScreen].scale; + CGSize expectedSize = OGAspectFit(TEST_IMAGE_SIZE, TEST_SCALE_SIZE); + if (NO == CGSizeEqualToSize(image.scaledImage.size, expectedSize)) { + [self notify:kGHUnitWaitStatusFailure]; + } else { + [self notify:kGHUnitWaitStatusSuccess]; + } + return; } - return; + } + else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } - (void)testScaledImage1 { [self prepare]; OGScaledImage *image = [[OGScaledImage alloc] initWithURL:[NSURL URLWithString:TEST_IMAGE_URL_STRING] size:TEST_SCALE_SIZE key:nil]; - [image addObserver:self]; + [image addObserver:self context:&KVOContext]; [self waitForStatus:kGHUnitWaitStatusSuccess timeout:10.]; - [image removeObserver:self]; + [image removeObserver:self context:&KVOContext]; } @end diff --git a/README.md b/README.md index b462547..63473a6 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,12 @@ over HTTP in a simple, extensible interface. /* * This is shorthand for calling KVO methods for @"image", @"scaledImage", and @"error" */ - [ogImage addObserver:self]; + [ogImage addObserver:self context:&KVOContext]; // check to see if the image loaded instantly (e.g., from cache) if (nil != ogImage.image) { // we already have an image, so do whatever we need with it, otherwise - // we'll be notified in `observeValueInKeyPath` whenever the image changes + // we'll be notified in `observeValueForKeyPath:ofObject:change:context:` whenever the image changes [self displayImage:ogImage.image]; // ooh, we also got all the image's metadata! Sweet! NSDictionary *exifData = [ogImage.originalFileProperties valueForKey:kCGImagePropertyExifDictionary]; @@ -66,16 +66,21 @@ placeholder image to use until loading is complete with ... OGImage *image = [[OGImage alloc] initWithURL:[NSURL URLWithString:@"http://somedomain.com/someimage.jpg"]]; -[image addObserver:self]; +[image addObserver:self context:&KVOContext]; ... - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - if ([keyPath isEqualToString:@"image"]) { - // image was loaded! - ... - } else if ([keyPath isEqualToString:@"error"]) { - // error loading image + if ((void *)&KVOContext == context) { + if ([keyPath isEqualToString:@"image"]) { + // image was loaded! + ... + } else if ([keyPath isEqualToString:@"error"]) { + // error loading image + } + } + else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } ``` @@ -100,16 +105,20 @@ OGScaledImage *image = [[OGScaledImage alloc] initWithURL:imageURL size:scaledSi * Note that here we're interested in the `scaledImage` property, not the full-size `image` * property. */ -[image addObserver:self]; +[image addObserver:self context:&KVOContext]; ... - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - if ([keyPath isEqualToString:@"scaledImage"]) { - // image was loaded and scaled! - ... - } else if ([keyPath isEqualToString:@"error"]) { - // error loading image + if ((void *)&KVOContext == context) { + if ([keyPath isEqualToString:@"scaledImage"]) { + // image was loaded and scaled! + ... + } else if ([keyPath isEqualToString:@"error"]) { + // error loading image + } + else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } ```