How could this constructor code be improved?
Why -init... should be declared to return id

Imagine you have class A and its subclass B sharing the same designated initializer, initWithString:.

@interface A : NSObject
-(A *) initWithString: (NSString *) string;
@end

@interface B : A
-(B *) initWithString: (NSString *) string;
@end


As you can see, the declarations have a conflicting return type, which unavoidably causes a compiler warning. You can trivially fix it by changing the methods to return id, which, given Objective-C dynamic typing, doesn't change anything about how these methods work. So it has become a well-established, but not as well-understood, tradition.

Why class initializers should use self rather than the class name

As you correctly noticed, using JGProduct instead of self will allocate an instance of JGProduct for any subclass, which is not what you want in 99% cases.

Why write +[JGProduct productWithIdentifier:]?

Most of the time, it's just a shortcut to alloc, init and autorelease to make calling code more readable. However, these initializers may be much more complicated and more efficient when implemented in class clusters. When you write a class cluster, you have one public superclass and several private subclasses. In such cases the superclass's alloc has to return a placeholder object which will allocate and instantiate an object of the right subclass in its init... implementation. The class initializer, on the other hand, can immediately return an already inited object of the right subclass.