When the app is run on an iPhone or simulator, tapping the screen spawns a dog class and displays an image of the dog.I'd like comments, issues, whatever. Is this a decent first Objective-C project, and can others learn from it?The code is meant to demonstrate Objective-C, Cocoa and UIKit. Here's a link to the full project.Primary files in the project:ProtocolsGKLiving.h////  GKLiving.h//  SampleApp//// Cocoa foundation classes#import <Foundation/Foundation.h>#pragma mark - Defines#pragma mark - The Living protocol of the GK namespace@protocol GKLiving <NSObject>#pragma mark - Mandatory methods#pragma mark - Optional methods@optional@endGKAnimalia.h////  GKAnimalia.h//  SampleApp//// Cocoa foundation classes#import <Foundation/Foundation.h>#import GKLiving.h#pragma mark - Defines#pragma mark - The Animalia protocol of the GK namespace@protocol GKAnimalia <GKLiving>#pragma mark - Mandatory methods  + (NSString *)stringRepresentationOfBreed;#pragma mark - Optional methods@optional@endGKCanidae.h////  GKCanidae.h//  SampleApp//// Cocoa foundation classes#import <Foundation/Foundation.h>#pragma mark - Defines#define GKCANIDAE_UNKNOWN_BREED @Mutt#pragma mark - The Canidae protocol of the GK namespace@protocol GKCanidae <GKAnimalia>#pragma mark - Mandatory methods  // Note that the + makes this a class-level method (it is  // not an instance method).  + (NSString *)says;#pragma mark - Optional methods@optional@endDog ClassesGKDog.h////  GKDog.h//  SampleApp//// Cocoa foundation classes#import <Foundation/Foundation.h>// Protocols#import GKAnimalia.h#import GKCanidae.h#pragma mark - Defines#define GKDOG_PRIVATE_THOUGHTS @I love you#define GKDOG_SOUND @Arf#define GKDOG_PLACEHOLDER_PATH \  [[NSBundle mainBundle] pathForResource:@how-to-draw-a-dog-4 ofType:@jpg]#pragma mark - The Dog class of the GK namespace// 1. No namespaces in Objective-C, so class prefixes are used instead.// The NS prefix (for NextStep, I assume) is pretty common.// 2. This class conforms to the GKCanidae protocol.// For a truer take on protocol naming conventions, see this article:// http://stackoverflow.com/questions/7483813/protocol-naming-in-objective-c//@interface GKDog : NSObject <GKCanidae>#pragma mark - Properties with getters/setters  @property (strong, nonatomic) NSString *name;  @property (strong, nonatomic) NSString *breed;  @property (assign, nonatomic) NSInteger age;  // A cute picture of the dog  @property (strong, nonatomic) NSString *pictureUrlString;#pragma mark - Instance methods  - (void)becomeMutt;@endGKYorkshireTerrier.h////  GKYorkshireTerrier.h//  SampleApp//#import GKDog.h#pragma mark - Defines#define GKYORKSHIRETERRIER_BREED @Yorkie#define GKYORKSHIRETERRIER_PICTURE_URL @http://www.acuteaday.com/blog/wp-content/uploads/2010/12/yorkie-puppy-091210.jpg#pragma mark - The YorkshireTerrier class of the GK namespace@interface GKYorkshireTerrier : GKDog@endGKYorkshireTerrier.m////  GKYorkshireTerrier.m//  SampleApp//#import GKYorkshireTerrier.h@implementation GKYorkshireTerrier#pragma mark - Class methods from GKAnimalia+ (NSString *)stringRepresentationOfBreed{  return GKYORKSHIRETERRIER_BREED;}#pragma mark - Initializers- (instancetype)init{  self = [super init];  if (self)  {    self.breed = [GKYorkshireTerrier stringRepresentationOfBreed];    self.pictureUrlString = GKYORKSHIRETERRIER_PICTURE_URL;  }  return self;}- (instancetype)initWithName:(NSString *)name{  self = [self init];  if (self)  {    self.name = name;  }  return self;}- (instancetype)initWithName:(NSString *)name andAge:(NSInteger)age{  self = [self initWithName:name];  if (self)  {    self.age = age;  }  return self;}@endMain Dog SpawningGKDogSpawner.h////  GKDogSpawner.h//  SampleApp//// Cocoa foundation classes#import <Foundation/Foundation.h>#pragma mark - Defines#define GKDOGSPAWNER_IMAGE_MIN_X 0.0f#define GKDOGSPAWNER_IMAGE_MAX_X ([UIScreen mainScreen].bounds.size.width - GKDOGSPAWNER_IMAGE_WIDTH)#define GKDOGSPAWNER_IMAGE_MIN_Y 0.0f#define GKDOGSPAWNER_IMAGE_MAX_Y ([UIScreen mainScreen].bounds.size.height - GKDOGSPAWNER_IMAGE_HEIGHT)#define GKDOGSPAWNER_IMAGE_WIDTH 64.0f#define GKDOGSPAWNER_IMAGE_HEIGHT 64.0f#pragma mark - The DogSpawner class of the GK namespace@interface GKDogSpawner : NSObject#pragma mark - Instance methods  - (void)spawnDogWithClassNamed:(NSString *)className onView:(UIView *)targetView;@endGKDogSpawner.m////  GKDogSpawner.m//  SampleApp//#import GKDogSpawner.h#import GKDog.h#import GKYorkshireTerrier.h#import GKRandomNumber.h// AFNetworking// https://github.com/AFNetworking/AFNetworking#import UIImageView+AFNetworking.h@implementation GKDogSpawner#pragma mark - Instance methods- (void)spawnDogWithClassNamed:(NSString *)className onView:(UIView *)targetView{  // Create a dog instance of the specified class  Class dogMetaClass = NSClassFromString(className);  GKDog *newDog = [[dogMetaClass alloc] init];  // Just for fun...  if ([newDog isKindOfClass:[GKYorkshireTerrier class]])  {    NSLog(@Whoa, you spawned a %@! They typically say %@ regularly., [newDog breed], [dogMetaClass says]);  }  // Create a UIImage from the placeholder's local path  UIImage *placeholderImage = [UIImage imageWithContentsOfFile:GKDOG_PLACEHOLDER_PATH];  // Create an NSURL object from the picture's URL string  NSURL *pictureUrl = [NSURL URLWithString:[newDog pictureUrlString]];  // -- Create a UIImageView and populate its image from the picture URL.  // -- While it's loading, the placeholder will be shown.  // -- The -setImageWithURL:placeholderImage: method is from the UIImageView+AFNetworking  // category on UIImageView; it provides plugin functionality that is not native to the base  // UIImageView class.  CGFloat x = [GKRandomNumber floatFrom:GKDOGSPAWNER_IMAGE_MIN_X to:GKDOGSPAWNER_IMAGE_MAX_X];  CGFloat y = [GKRandomNumber floatFrom:GKDOGSPAWNER_IMAGE_MIN_Y to:GKDOGSPAWNER_IMAGE_MAX_Y];  CGRect dogImageFrame = CGRectMake(x, y, GKDOGSPAWNER_IMAGE_WIDTH, GKDOGSPAWNER_IMAGE_HEIGHT);  UIImageView *dogImageView = [[UIImageView alloc] initWithFrame:dogImageFrame];  [dogImageView setImageWithURL:pictureUrl placeholderImage:placeholderImage];  // Add the dog image view as a child of the target view. This will make the image visible.  [targetView addSubview:dogImageView];}@endGesture RecognizersGKTapHandler.h////  GKTapHandler.h//  SampleApp//// Cocoa foundation classes#import <Foundation/Foundation.h>#pragma mark - Defines#pragma mark - The TapHandler class of the GK namespace@interface GKTapHandler : NSObject <UIGestureRecognizerDelegate>#pragma mark - Instance methods  // Use IBAction to link methods to the Storyboard  - (IBAction)handleTouch:(id)sender;@endGKTapHandler.m////  GKTapHandler.m//  SampleApp//#import GKTapHandler.h#import GKDogSpawner.h#import GKRandomNumber.h@implementation GKTapHandler#pragma mark - Instance variables{  GKDogSpawner *_dogSpawner;  NSArray *_dogTypes;}#pragma mark - Initializers- (instancetype)init{  self = [super init];  if (self)  {    // Initialize the dog spawner    self->_dogSpawner = [[GKDogSpawner alloc] init];    // Initialize and populate the dog types. Note the nil guard value.    self->_dogTypes = [NSArray arrayWithObjects:      @GKLhasaApso,      @GKYorkshireTerrier,      nil];  }  return self;}#pragma mark - Instance methods- (IBAction)handleTouch:(id)sender{  NSUInteger totalDogTypes = self->_dogTypes.count;  NSUInteger randomDogTypeIndex = [GKRandomNumber unsignedIntFrom:0 to:totalDogTypes];  NSString *dogType = [self->_dogTypes objectAtIndex:randomDogTypeIndex];  id applicationDelegate = [[UIApplication sharedApplication] delegate];  UIView *targetView = [applicationDelegate window].rootViewController.view;  [self->_dogSpawner spawnDogWithClassNamed:dogType onView:targetView];}@endUtility ClassesGKRandomNumber.h////  GKRandomNumber.h//  SampleApp//// Cocoa foundation classes#import <Foundation/Foundation.h>#pragma mark - Defines#pragma mark - The RandomNumber class of the GK namespace@interface GKRandomNumber : NSObject#pragma mark - Class methods  + (NSUInteger)unsignedIntFrom:(NSUInteger)min to:(NSUInteger)max;  + (float)floatFrom:(NSUInteger)min to:(NSUInteger)max;@endGKRandomNumber.m////  GKRandomNumber.m//  SampleApp//#import GKRandomNumber.h// Required for arc4random_uniform#include <stdlib.h>@implementation GKRandomNumber#pragma mark - Class methods+ (NSUInteger)unsignedIntFrom:(NSUInteger)min to:(NSUInteger)max{  NSUInteger range = max - min;  u_int32_t generatedInteger = arc4random_uniform((u_int32_t)range);  NSUInteger result = generatedInteger + min;  return result;}+ (float)floatFrom:(NSUInteger)min to:(NSUInteger)max{  return (float)[self unsignedIntFrom:min to:max];}@endView ControllersGKViewController.h////  GKViewController.h//  SampleApp//// Main library for the iOS user interface#import <UIKit/UIKit.h>#pragma mark - Defines#pragma mark - The ViewController class of the GK namespace@interface GKViewController : UIViewController  // Use IBOutlet to link properties to the Storyboard  @property (weak, nonatomic) IBOutlet UITapGestureRecognizer *tapRecognizer;@end
Spawning a Dog class
objective c;ios;cocoa
Because this question is so, so large, I won't get into all the specifics of everything I see.  I will point out some things, and provide some examples from one file or another, and as you work through my answer, you should work through your project to find all the other instances of an example I point out.I will start with a simple answer to the topic question:Is this a decent first Objective-C project, and can others learn from it?Simply, yes.  I haven't built and compiled and tried running this, but I assume you have.  Certainly anyone whose Objective-C knowledge is below that of this project would be able to learn from it.  And it's fairly well organized, clean, etc, so I'll pass it as decent as well.But in the first few paragraphs, you talk about wanting for a project to serve as an example of Objective-C standard practice.  A perfectly fine want--but let's be clear, this project isn't that.Also, while I did say that someone could learn from this project, I think the audience of people who would take the time to learn from this is fairly narrow.  At least in my personal experience as a programmer, I learn best when adding small chunks of knowledge at a time.  To me, learning programming is like having a rubber band ball.  It's really hard to get that ball started.  But once you do, all you have to do to keep it going is snap one more rubber band on here and there.Your project is, in my opinion, a bit too complex for Objective-C and iOS beginners and covers far too much ground.  And the project contains some problems that if a more advanced Objective-C user learned as the way to do it, he wouldn't have benefited all that much.So, now that that's out of the way, I'll start at the top, and work my way down.It is likely that this answer my be broken into multiple answers or will receive future edits.  Basically, treat this as an answer in progress, as there's quite a few things here I want to address, and I won't be able to address it all in one sitting--you didn't write this whole project in one sitting, did you?First of all, some of the problems that are consistent throughout the entirety of the project:EDIT: As a note here, I'm pointing to sections of your code you've marked off with a #pragma mark.  I wanted to come back and edit in some clarity.  The #pragma mark themselves are for the most part okay.  These are basically just comments with some special features, and using #pragma marks to mark off sections is great.  I'm mostly discussing the content in each of these sections.#pragma mark - Namespace ...// 1. No namespaces in Objective-C, so class prefixes are used instead.// The NS prefix (for NextStep, I assume) is pretty common.Correct and correct.  NS does stand for NextStep.  In iOS development, most of the Foundation classes you'll use are prefixed with NS or UI.  You'll run into some other common ones too like CG, AF, etc.But more importantly, you're correct about the fact that there are no namespaces in Objective-C.  As such, a project hoping to serve as the standard practice for Objective-C shouldn't have a #pragma mark - Namespace in every single header file in its project.  True Objective-C projects should have this no where.  Best case scenario, you might see it in an Objective-C++ project.It is perfectly fine for a programmer coming from a non-Objective-C background to do something like this if it helps the organization of the project because he's used to thinking of it in some other way, but it's definitely not standard practice.#pragma mark - DefinesYou've included this line in most of the files.  The fact of the matter is, you shouldn't be using #define so often that it's a regularly occurring section in your code.  Certainly, you shouldn't be using #define simply for constant values.  That's what the const keyword is for.  And if you need to declare a constant value in a .h file so it can be seen by multiple files, well, that's what the extern keyword is for.So for example this:#define GKDOGSPAWNER_IMAGE_MIN_X 0.0fShould be replaced with this:extern CGFloat const DKDOGSPAWNER_IMAGE_MIN_X;in the .h, and then define it in the .m of the same file:CGFloat const DKDOGSPAWNER_IMAGE_MIN_X = 0.0f;Applying this thinking to all of your defines eliminates all but 3 of the #defines.The last three could also potentially be eliminated via functions.  For example:#define GKDOGSPAWNER_IMAGE_MAX_X ([UIScreen mainScreen].bounds.size.width - GKDOGSPAWNER_IMAGE_WIDTH)could be replaced with:CGFloat GKDOGSPAWNER_IMAGE_MAX_X();in the .h, then define the function in the .m:CGFloat GKDOGSPAWNER_IMAGE_MAX_X() {    return ([UIScreen mainScreen].bounds.size.width - GKDOGSPAWNER_IMAGE_WIDTH);}In this case though, the #define doesn't bother me as much.  These points on #define aren't really even Objective-C specific.  They can apply across all of the C-Based languages that support preprocessor statements (though the syntax may vary slightly from language to language).#pragma mark - Mandatory methods#pragma mark - Optional methodsIt is fine to have these #pragma marks in, particularly in large protocols or just large files.  But having these marks does not excuse not marking the methods with code that actually makes methods required or optional.This is something that doesn't really translate unless you're in an IDE, but a #pragma mark and other codes show up in different colors.  In my current Xcode theme, all precompiler code (which includes #pragma mark) shows up as brown.  Things like @protocol, @required, @optional, and @end show up as pink.  So if I were to load up your code in Xcode, a quick glance at your protocols would show me the keyword @required never shows up.  It'd be a bit confusing.  Now, all methods in a protocol are by default @required (unless marked @optional), but if we're going to talk about standard practice, I am certainly of the opinion that a section of @required methods should be explicitly marked with the @required keyword.  It is my personal habit to individually mark every method in a protocol so there is no mistaking the intent of any of the protocol methods.  This may be a bit overboard for a standard practice, but I certainly think the @required keyword belongs, for clarity.GKRandomNumber.h / GKRandomNumber.mThere are a few problems I have with this class.First, it's not really a class, is it?  No one should ever instantiate an object of this class, and yet they could.  There are two fixes.  Fix one is to use preprocessor statements to prevent instantiation and subclassing.  I don't really like this fix, but it is a possibility.  Preventing instantiation looks like this in the .h file:+ (id)alloc __attribute__((unavailable(GKRandomNumber cannot be instantiated)));- (id)init __attribute__((unavailable(GKRandomNumber cannot be instantiated)));But this is a little silly.  Especially when the two methods in this class are so simple.  We don't need a class because we don't need Objective-C style methods.  We can simply use C-style functions:NSUInteger randomUnsignedInt(NSUInteger min, NSUInteger max);My second big problem with these files is that the method names don't say random in them--they should.  The name of the file or class isn't enough.  Consider NSArray or NSString, for example.  Look at all their methods.  If you're using an NSArray, you know you're dealing with an NSArray, but Apple says this isn't enough, and as such, all the methods look like this:arrayarrayWithArray:arrayWithContentsOfFile:arrayWithContentsOfURL:arrayWithObject:arrayWithObjects:arrayWithObjects:count:My third big problem with this pair of files is that you have a method for grabbing an integer in a range... but require only unsigned integers.  If I want to assure a positive number, I can just assure my minimum number is greater than zero, right?  Why are we dealing only with unsigned integers?Fourth, your method has no way of dealing with when the value sent for max is larger than the value sent for min.  Given we're dealing with UNSIGNED INTEGERS, this will be a big, big problem.  If you try to find a random number between 10 and 5, you won't get 6, 7, 8, or 9.  When you find the range (5-10) using unsigned ints, you'll get underflow, and it will wrap around to some number about 5 less than whatever the max for NSUInteger is (which will depend on system).  So your range will be almost the entire spectrum of unsigned ints.  When you add your min back (10, not 5), you will definitely be outside the range of 5 to 10.  The answer to this problem is to do things the way Apple has done.  Rather than taking a starting point and an ending point, you take a starting point and a range.Fifth, you're doing a lot of unhelpful and misleading castings.  The float version of your random number method doesn't really return a random float... it returns a random NSUInteger cast as a float.  And your NSUInteger doesn't really return a random NSUInteger in the given range... it returns a u_int32_t cast as an NSUInteger.u_int32_t is a typedef from C that is a 32-bit integer, no matter the operating system.NSInteger is a typedef from Objective-C.  On 32-bit systems it's a 32-bit integer.  On 64-bit systems, it's a 64-bit integer.float is a floating point number and not an integer.Again, I'm not super familiar with arc4random_uniform, and using u_int32_t may be a limitation of this function.  But if that's the case, then your Objective-C method should reflect this.  If you're using a u_int32_t range and getting the result from the random function as a u_int32_t, then the method should take u_int32_t arguments and return a u_int32_t value.  If the end user of this method needs to cast it as something else, then let them, but if the internals of the method do all the actual work in some particular data type, you should probably use that data type as the return type and the argument type.And this logic applies to the float version of the method.  To me, a method that says it returns a random float is a method that will return more than just an integer cast to a float.  If I want a random whole number to use as an argument to some method that expects a floating point number, then I need to use a method to generate a random int and cast it to a float myself or generate a random float and come up with some method for zeroing out the decimals.  Either way, I shouldn't be mislead by a method that claims to return a float and only returns integers cast as floats.