-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds class methods and strongly typed return values. #8
base: master
Are you sure you want to change the base?
Changes from 5 commits
880afd9
cd43136
795d560
85d9a15
eeed36e
7f12289
987c621
61fb2e5
bc442e3
60bd373
79a0a60
e78ed89
5b7c86c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#import <UIKit/UIKit.h> | ||
|
||
@interface CGTAFlagCollectionViewCell : UICollectionViewCell | ||
|
||
@property (nonatomic, weak) IBOutlet UIImageView *imageView; | ||
@property (nonatomic, copy) NSString *countryName; | ||
|
||
@end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#import "CGTAFlagCollectionViewCell.h" | ||
|
||
@implementation CGTAFlagCollectionViewCell | ||
@end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ | |
|
||
@interface CGTAImagesCatalog (RuntimeHackery) | ||
|
||
+ (NSArray *)allImageNames; | ||
+ (NSArray *)allImages; | ||
|
||
@end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,13 +15,33 @@ | |
|
||
@implementation CGTAImagesCatalog (RuntimeHackery) | ||
|
||
+ (NSArray *)allImageNames; | ||
{ | ||
NSMutableArray *imageNames = [NSMutableArray array]; | ||
unsigned int count; | ||
Method *methods = class_copyMethodList(object_getClass(self), &count); | ||
for (unsigned int index = 0; index < count; index++) { | ||
SEL methodName = method_getName(methods[index]); | ||
if (sel_isEqual(methodName, _cmd) || sel_isEqual(methodName, @selector(allImages))) { | ||
continue; | ||
} | ||
NSString *imageName = NSStringFromSelector(method_getName(methods[index])); | ||
// remove the "Image" suffix | ||
imageName = [imageName substringToIndex:[imageName length] - [@"Image" length]]; | ||
[imageNames addObject:[imageName uppercaseString]]; | ||
} | ||
free(methods); | ||
return imageNames; | ||
} | ||
|
||
+ (NSArray *)allImages; | ||
{ | ||
NSMutableArray *images = [NSMutableArray array]; | ||
unsigned int count; | ||
Method *methods = class_copyMethodList(object_getClass(self), &count); | ||
for (unsigned int index = 0; index < count; index++) { | ||
if (sel_isEqual(method_getName(methods[index]), _cmd)) { | ||
SEL methodName = method_getName(methods[index]); | ||
if (sel_isEqual(methodName, _cmd) || sel_isEqual(methodName, @selector(allImageNames))) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that you're doing this twice in subtly different ways, maybe it's worth having a list somewhere of the runtime hackery methods to compare against instead? |
||
continue; | ||
} | ||
id image = method_invoke(self, methods[index]); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,19 +11,13 @@ | |
#import "CGTADetailViewController.h" | ||
#import "CGTAImagesCatalog+RuntimeHackery.h" | ||
#import "CGTAMainStoryboardIdentifiers.h" | ||
|
||
|
||
@interface CGTAFlagCollectionViewCell : UICollectionViewCell | ||
|
||
@property (nonatomic, weak) IBOutlet UIImageView *imageView; | ||
|
||
@end | ||
|
||
#import "CGTAFlagCollectionViewCell.h" | ||
|
||
@interface CGTAMasterViewController () | ||
|
||
@property (nonatomic, weak) IBOutlet UISlider *cellSizeSlider; | ||
@property (nonatomic, strong) NSArray *flagImages; | ||
@property (nonatomic, strong) NSArray *flagImageNames; | ||
|
||
@end | ||
|
||
|
@@ -41,9 +35,11 @@ - (void)awakeFromNib; | |
|
||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender; | ||
{ | ||
if ([segue.identifier isEqualToString:CGTAMainStoryboardTapOnFlagIdentifier]) { | ||
if ([segue.identifier isEqualToString:[self tapOnFlagSegueIdentifier]]) { | ||
CGTADetailViewController *detailViewController = segue.destinationViewController; | ||
detailViewController.image = ((CGTAFlagCollectionViewCell *)sender).imageView.image; | ||
CGTAFlagCollectionViewCell *cellSender = sender; | ||
detailViewController.image = cellSender.imageView.image; | ||
detailViewController.countryName = cellSender.countryName; | ||
} | ||
} | ||
|
||
|
@@ -58,17 +54,26 @@ - (IBAction)sliderValueChanged:(UISlider *)sender; | |
|
||
- (NSArray *)flagImages; | ||
{ | ||
NSArray *allFlagImages = nil; | ||
|
||
// Initial version: full of strings that you have to type correctly! | ||
// Misspell any of these and your app will crash on trying to add `nil` to an array. | ||
allFlagImages = @[[UIImage imageNamed:@"USA"], [UIImage imageNamed:@"Canada"], [UIImage imageNamed:@"UK"], [UIImage imageNamed:@"Australia"]]; | ||
|
||
// New version: get the properly compiler-checked spelling from the image catalog. | ||
allFlagImages = @[[CGTAImagesCatalog usaImage], [CGTAImagesCatalog canadaImage], [CGTAImagesCatalog ukImage], [CGTAImagesCatalog australiaImage]]; | ||
if (!_flagImages) { | ||
// Initial version: full of strings that you have to type correctly! | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of "Initial version", how about "What you might have done without this tool" |
||
// Misspell any of these and your app will crash on trying to add `nil` to an array. | ||
_flagImages = @[[UIImage imageNamed:@"USA"], [UIImage imageNamed:@"Canada"], [UIImage imageNamed:@"UK"], [UIImage imageNamed:@"Australia"]]; | ||
|
||
// New version: get the properly compiler-checked spelling from the image catalog. | ||
_flagImages = @[[CGTAImagesCatalog usaImage], [CGTAImagesCatalog canadaImage], [CGTAImagesCatalog ukImage], [CGTAImagesCatalog australiaImage]]; | ||
|
||
// But really, why not use a little runtime hackery because we can? | ||
_flagImages = [CGTAImagesCatalog allImages]; | ||
} | ||
return _flagImages; | ||
} | ||
|
||
// But really, why not use a little runtime hackery because we can? | ||
return [CGTAImagesCatalog allImages]; | ||
- (NSArray *)flagImageNames; | ||
{ | ||
if (!_flagImageNames) { | ||
_flagImageNames = [CGTAImagesCatalog allImageNames]; | ||
} | ||
return _flagImageNames; | ||
} | ||
|
||
#pragma mark - UICollectionViewDataSource | ||
|
@@ -85,13 +90,17 @@ - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSe | |
|
||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath; | ||
{ | ||
CGTAFlagCollectionViewCell *cell = (CGTAFlagCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CGTAMainStoryboardImageCellIdentifier forIndexPath:indexPath]; | ||
CGTAFlagCollectionViewCell *cell = nil; | ||
|
||
// Initial version: we must type in the identifier, and have no guarantees as to which class it returns | ||
cell = (CGTAFlagCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"Image Cell" forIndexPath:indexPath]; | ||
|
||
// New version: class extension which returns the exact type we are expecting | ||
cell = [self dequeueImageCellForIndexPath:indexPath ofCollectionView:collectionView]; | ||
|
||
cell.imageView.image = self.flagImages[indexPath.item]; | ||
cell.countryName = self.flagImageNames[indexPath.item]; | ||
return cell; | ||
} | ||
|
||
@end | ||
|
||
|
||
@implementation CGTAFlagCollectionViewCell | ||
@end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Holy equality comparisons between floating-point numbers and integer literals, Batman!
(Seriously, while this does work in this case, it's probably a bad idea to do this kind of thing in example code that will be copied ad nauseam.)