Objective C class inheritance with factory methods - iphone

I would like to inherit from a framework class that has a factory method. How can I make the factory method return an object of my inherited class type? I found this useful article which describe a similar situation but in their case you have control over the superclass. How could I write, say, a subclass of UIImage that imageNamed: would return an object of my subclass type?

I would like to inherit from a framework class that has a factory method. How can I make the factory method return an object of my inherited class type?
This is all you should have to do:
#interface MONImage : UIImage
#end
#implementation MONImage
#end
Then:
MONImage * image = [MONImage imageNamed:name];
How could I write, say, a subclass of UIImage that imageNamed: would return an object of my subclass type?
+[UIImage imageNamed:]'s implementation wrote subclassers out of this approach. Consequently, you would need to implement this method yourself.
Here's how one should declare a factory method:
+ (instancetype)imageNamed:(NSString *)pName;
and how one should implement it:
+ (instancetype)imageNamed:(NSString *)pName
{
MONImage * image = [[self alloc] initWithThisDesignatedInitializer:pName];
^^^^ NOTE: self, not a concrete class
...set up image...
return image;
}
but they did not do it that way -- +[UIImage imageNamed:] wrote subclasses out and returns a UIImage when you write MONImage * img = [MONImage imageNamed:pName];. Sometimes that is done for a good reason. Some methods should have 'final' semantics. This often appears when your method may return multiple types, as in a class cluster. The language does not express 'final' methods -- but such a method should at least be documented.
So to come around to this UIImage case:
#interface MONImage : UIImage
+ (instancetype)imageNamed:(NSString *)pName;
#end
#implementation MONImage
+ (instancetype)imageNamed:(NSString *)pName
{
UIImage * source = [UIImage imageNamed:pName];
CGImageRef cgImage = source.CGImage;
if (cgImage)
return [[self alloc] initWithCGImage:cgImage];
// try it another way
return nil;
}
#end
Note that UIImages and CGImages are immutable. This should not result result in a deep copy of the image data.

For your example:
Subclass UIImage to, say, MyImage
Implement the imageNamed: method to do anything specific that you need to be done.
Call that method on that class: MyImage *newImage = [MyImage imageNamed:imageName];

The approach that solved my problem was to use a category instead of inheritance (credits go to Jonathan Cichon in the comments of my question). I used Associative References to declare and store additional data in the category implementation as discussed a lot here in SO. I would like to drive the attention to the NSObject category implementation proposed by Jonathan that makes really easy and elegant to add associative references to any object.

Related

Using NSCopy to Copy a Custom Object Containing Pointers?

I am learning how to use NSCopy. I want to make a copy of a custom object I am using, which is an ImageView in a UIScrollView.
I am trying to implement NSCopying protocol as follows :
-(id)copyWithZone:(NSZone *)zone
{
ImageView *another = [[ImageView allocWithZone:zone]init];
another.imageView = self.imageView;
another.imageToShow = self.imageToShow;
another.currentOrientation = self.currentOrientation;
another.portraitEnlarge = self.portraitEnlarge;
another.landscapeEnlarge = self.landscapeEnlarge;
another.originalFrame = self.originalFrame;
another.isZoomed = self.isZoomed;
another.shouldEnlarge = self.shouldEnlarge;
another.shouldReduce = self.shouldReduce;
another.frame = self.frame;
//another.delegate = another;
another.isZoomed = NO;
[another addSubview:another.imageView];
return another;
}
Then to copy the object in another class :
ImageView * onePre = [pictureArray objectAtIndex:0];
ImageView * one = [onePre copy];
The copy is made however I have one odd problem. The copied object's ImageView (a UIImageView) and ImageToShow (a UIImage) properties seem to be the same as the original objects. This kind of makes sense as in the copy code I am re-pointing a pointer, rather than making a new version of ImageView and ImageToShow.
My question is how do I make a copy of an object that contains pointers to other objects ?
Thanks !
UIView does not conform to NSCopying, but it does conform to NSCoding:
another.imageView = [NSKeyedUnarchiver unarchiveObjectWithData:
[NSKeyedArchiver archivedDataWithRootObject:self.imageView]];
This serializes and then deserializes the object, which is the standard way to perform a deep copy in ObjC.
EDIT: See https://stackoverflow.com/a/13664732/97337 for an example of a common -clone category method that uses this.

Trouble with Core Data Transformable Attributes for Images

I am stuck on what is supposed to be a very simple thing to do: have a Core Data Entity store / display (through bindings) an image assigned as a transformable attribute.
I've read many related posts on the Stack (e.g., see here and here), but am still having trouble with it, after having developed sample code and researched other articles (e.g., see here as well as here). This is related to my earlier question, which I still have not resolved.
I created a simple doc-based Core Data App to demonstrate the problem. The Core Data managed object is called "TheEntity" and the attribute "theImageAtt." The entity as defined in Core Data is shown below (ImageValueTransformer is the NSValueTransformer):
I let XCode generate the NSManagedObject subclass header and implementation files (I left out the code for the "name" attribute to make it simpler):
// TheEntity.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "ImageValueTransformer.h"
#interface TheEntity : NSManagedObject
#property (nonatomic, retain) NSImage * theImageAtt;
#end
-----------------------
// TheEntity.m
#import "TheEntity.h"
#implementation TheEntity
#dynamic theImageAtt;
#end
Below are the header and implementation files for my "ImageValueTransformer." Lots of examples of this on the Stack and elsewhere (the tiff rep is arbitrary).
// ImageValueTransformer.h
#import <Foundation/Foundation.h>
#interface ImageValueTransformer : NSValueTransformer
#end
-------------------------------
// ImageValueTransformer.m
#import "ImageValueTransformer.h"
#implementation ImageValueTransformer
+ (BOOL)allowsReverseTransformation {return YES;}
+ (Class)transformedValueClass {
return [NSData class]; // have also tried: return [NSImage class];
}
- (id)transformedValue:(id)value {
NSData *data = [value TIFFRepresentation];
return data;
}
- (id)reverseTransformedValue:(id)value {
NSImage *imageRep = [[NSImage alloc] initWithData:value];
return imageRep;
}
#end
The Value Transformer can be initialized / registered by allocating an instance of it in MyDocument.m, but in the end, it doesn't matter that much as long as the transformer header is imported into the theEntity Header (see above). I have experimented with this and it does not remove the error I get below. For reference, there is earlier discussion on whether or not the value transformer needs to be registered (see the comments by CornPuff and Brian Webster).
Back to the problem at hand, a good code example from Apple is here which shows an alternative initialization of the value transformer, I tried that setup too.
Putting this into action, I have a method to load a test image and assign it to the transformable attribute in MyDocument.m (from a selected Entity instance in an NSTable):
- (IBAction)addImg:(id)sender {
NSImage *theImg = [[NSImage alloc] initWithContentsOfFile:#"/Desktop/testImage.jpg"];
//[theImageView setImage:theImg]; // as a test, this displays ok
// "theEntities" below are defined as an IBOutlet to my Array Controller:
[theEntities setValue:theImg forKeyPath:#"selection.theImageAtt"];
NSLog(#"after setting the image ..."); // this never logs
}
Zeroing-in on where the code breaks, the line below:
[theEntities setValue:theImg forKeyPath:#"selection.theImageAtt"];
gives the error:
Cannot create BOOL from object <4d4d002a 0003717e 8989898a 8a8a8b8b 8b8b8b8b
8a8a8a89 89898888 88878787 8a8a8a89 89898888 88888888 88888889 89898a8a
8a8a8a8a 8b8b8b88 88888787 87898989 8a8a8a89 89898a8a 8a8c8c8c 8b8b8b8a
8a8a8888 .... and so on for the size of the Image array ...
If I comment out the said line above then my NSTable populates just fine (so the bindings and array controller seem ok), but of course with no image in the NSImageView.
As a check, the conversion code used in the Image Transformer works as expected (this is tested separately from the value transformer):
// Image to Data Conversion:
NSImage *imageIn = [[NSImage alloc] initWithContentsOfFile:#"testImage.jpg"];
NSData *imgData = [imageIn TIFFRepresentation];
NSImage *imageOut = [[NSImage alloc] initWithData:imgData];
[theImageDisplay setImage:imageOut];
What am I missing on this?
I found that the error reported above, namely,
Cannot create BOOL from object ...
does not occur when using an Image Well or Image Cell (subclasses of NSImageView) rather than the Custom View that I was trying to write to earlier.
So for now I'm using the default value transformer rather than a custom value transformer. This is a workable solution, but academically speaking, it would be nice to know why the default Custom View led to errors when binding to a Core Data attribute (defined as transformable in the Core Date Model).
Digging into this a little further, the Image Well inherits from NSImageView, so at least one difference is that they are distinct with regard to the "editable" property (Image Wells are editable which plays well with Drag-n-Drop). So in an attempt to reconcile these two, I set my Custom View to editable, thinking that this might resolve the problem:
theImageView = [[NSImageView alloc] init];
[theImageView setEditable:YES];
But it must be something else, this does not resolve the error above. For now at least, I have a workable solution. Should others encounter this, I hope these notes are helpful!

Static UIImage in whole application

I want to have an static UIImage so I could access it from different classes. I've tried this way, but didn't worked:
Made Constans.h file with:
static UIImage *myImage;
And after that I import this header where it's needed. I thought that at this moment myImage was static and any changes made on this object would be visible everywhere. But it looks like every class is working on it's own myImage instance. Is there any way to have such static UIImage?
Edit:
Property in AppDelegate works fine. I have now static UIImage, but still I don't have effect I was expecting.
I have an UIImageView in ViewController. I load an image to my delegate.myImage and after I do:
delegate.myImage = [UIImage imageNamed:#"blah.png"];
myImageView.image = delegate.myImage;
Image is loaded, but after I want to change it in AppDelegate, but when I change myImage this way:
delegate.myImage = [UIImage imageNamed:#"blah2.png"];
nothing change in myImageView. It's like myImageView.image = delegate.myImage copied memory address of myImage so after if I change reference of myImage it's not affecting myImageView.image. I wanted to have an UIImage that after any changes it would also affect myImageView.
Is there other way than having an reference to myImageView in AppDelegate?
Rather than making an explicitly application-wide image, just use [UIImage imageNamed:]. This handles caching of the image for you! Whereever you need to use the image, just access it like so:
[UIImage imageNamed:#"imageName.png"]
Note: this will cause there to be a single copy of the image in memory. You can't unload it -- but newer versions of iOS may unload it behind the scenes upon low memory conditions.
See also the API docs for [UIImage imageNamed:].
Btw, imageNamed is often used for small images that get used multiple times -- e.g. table cell images -- but there's no reason to not use it on large images if you genuinely want a static app-wide image.
The keyword static makes a variable local to the compilation unit where it id defined. This means you can safely have the same symbol defined in multiple .c files; all those declarations will not collide and each file will have its own private symbol.
Put simply, if you really want to define a global variable that is accessed by any part of your program, you do not need the static keyword. In this case, though, the "trick" is declaring the variable in a header file (that you include everywhere the global should be visible) like this:
extern UIImage *myImage;
and then provide a definition for that variable in one single place (.c file) without the static keyword. The extern keyword tells the compiler that the definition for that symbol is not found inside of the current compilation unit (.c file), but in a different one.
Now, as many others have pointed out, you could better do that by means of a singleton, although it is usually recognized that using a singleton to mask a global variable is usually a way to mask a design problem.
That's a C problem (not specifically related to Objective-C or iOS)
The static keyword make the variable sticky inside its compilation unit.
When you #include (or #import in ObjC) a header, that's like if its content were copied & pasted into the file that includes it. As a reminder, ".h" files are not compiled (they are just included in ".m" files that themselves compile)
So that works exactly the same way as if you were typing the same lines of code you have in your .h in any file that #include it.
This explains why in each of your source files that #include "Constants.h" they each see a different instance of the myImage variable.
Instead you should:
Use the Singleton Pattern, that is specifically made for such cases
Or use the static keyword in an implementation file ("Constants.m") to make this variable sticky inside the compilation unit of this "Constants.m" file
I highly recommand to go with the Singleton Pattern for such cases anyway. More info on Singleton Pattern here in the Apple official DevPedia
You can create a #property (nonatomic, retain) UIImage *image; in your app delegate and in every class you want to use the image you can create AppDelegate *delegate=(AppDelegate *)[[UIApplication sharedApplication] delegate]; and then access to the UIImage from the delegate object like this :
[imageView setImage:[delegate image]];
Or you can use a class like this :
header file
#interface Data : NSObject
#property (nonatomic, strong) UIImage *image;
+ (Data *)sharedInstance;
+ (id)allocWithZone:(NSZone*)zone;
- (id)init;
- (id)copyWithZone:(NSZone *)zone;
#end
implementation file
#implementation Data
#synthesize image;
static Data *sharedInstance=nil;
+ (Data *)sharedInstance {
if (sharedInstance == nil) {
sharedInstance = [[super allocWithZone:NULL] init];
}
return sharedInstance;
}
+ (id)allocWithZone:(NSZone*)zone {
return [self sharedInstance];
}
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
#end
Then, you have to import Data.h in every class you want and then use :
UIImageView *imageView=[[UIImageView alloc] init];
[imageView setImage:[[Data sharedInstance] image]];
This works great for me :)
Use the singleton pattern.
If your code is ARC follow this link http://lukeredpath.co.uk/blog/a-note-on-objective-c-singletons.html
In iPhone the AppDelegate class Acts a Static Class. so you can do the same thing which you have done in Constant.h in the YourAppDelegate Class. But dont use Static Keyword.
I am not very Sure but thinks it will work. :)
You can use UIImage category as example to get this picture.
In your .h file just add your static method.
#import <UIKit/UIKit.h>
#interface UIImage (StaticImage)
+(UIImage *)staticImage;
#end
And in your .m file do following steps:
#import "UIImage+StaticImage.h"
//This is your static image
static UIImage *myStaticImage;
#implementation UIImage (StaticImage)
+(void)initialize{
//Important to add this condition, because this method will be called for every
//child class of UIImage class
if (self == [UIImage class]){
myStaticImage = [[UIImage alloc] init];
}
}
+(UIImage *)staticImage{
//Just return your existing static image
return myStaticImage;
}
#end

How do I call methods in a class that I created dynamically with NSClassFromString?

The reason I am doing dynamic class loading is because I am creating a single set of files that can be used across multiple similar projects, so doing a #import and then normal instantiation just won't work. Dynamic classes allows me to do this, as long as I can call methods within those classes. Each project has this in the pch with a different "kMediaClassName" name so I can dynamically load different classes based on the project I'm in:
#define kMediaClassName #"Movie"
Here is the code I am using to get an instance of a class dynamically:
Class mediaClass = NSClassFromString(kMediaClassName);
id mediaObject = [[[mediaClass alloc] init] autorelease];
Then I try to call a method within that dynamic class:
[mediaObject doSomething];
When I then type this into Xcode, the compiler shows a warning that the class doesn't have this method, even though it does. I can see it right there in my Movie.h file. What is going on? How do I call a method from a dynamically instantiated class?
And what if I need to pass multiple arguments?
[mediaObject loadMedia:oneObject moveThe:YES moveA:NO];
Thanks for the help in advance.
you can declare a protocol, like so:
#protocol MONMediaProtocol
/*
remember: when synthesizing the class, you may want
to add the protocol to the synthesized class for your sanity
*/
- (BOOL)downloadMediaAtURL:(NSURL *)url toPath:(NSString *)path loadIfSuccessful:(BOOL)loadIfSuccessful;
/* ...the interface continues... */
#end
in use:
Class mediaClass = NSClassFromString(kMediaClassName);
assert(mediaClass);
id<MONMediaProtocol> mediaObject = [[[mediaClass alloc] init] autorelease];
assert(mediaObject);
NSURL * url = /* expr */;
NSString * path = /* expr */;
BOOL loadIfSuccessful = YES;
BOOL success = [mediaObject downloadMediaAtURL:url toPath:path loadIfSuccessful:loadIfSuccessful];
Well it might be there, but the Compiler doesn't know about it because it assumes that mediaClass is just some Class object, but nothing specific. NSClassFromString() is a runtime function and thus can't give the compiler a hint at compile time about the object.
What you can do:
Ignore the warning
Use [media performSelector:#selector(doSomething)];
And btw, this is wrong:
Class mediaClass; = NSClassFromString(kMediaClassName);
it should be:
Class mediaClass = NSClassFromString(kMediaClassName);
An easier and fancier solution than NSInvocation :)
Class mediaClass = NSClassFromString(kMediaClassName);
if(mediaClass){
id mediaObject = class_createInstance(mediaClass,0);
objc_msgSend(mediaObject, #selector(doSomethingWith:andWith:alsoWith:), firstP, secondP,thirdP);
}
Explanation:
class_createInstance(mediaClass,0); does exactly the same as [[mediaClass alloc] init];
if you need to autorelease it, just do the usual [mediaObject autorelease];
objc_msgSend() does exactly the same as performSelector: method but objc_msgSend() allows you to put as many parameters as you want. So, easier than NSInvocation right? BTW, their signature are:
id class_createInstance(Class cls, size_t extraBytes)
id objc_msgSend(id theReceiver, SEL theSelector, ...)
For more info you can refer the Objective-C Runtime Reference
As Joe Blow says, NSInvocation will help you here, though NSObject has a couple of shortcut methods that you can use: -performSelector:, -performSelector:withObject:, and -performSelector:withObject:withObject:.

Dealing with objects from different classes

I have 3 classes of objects. All 3 classes share some properties in common, as color, text, etc.
For example, I can have this
Class1 *objectA = [[Class1 alloc] init];
objectA.myColor = [UIColor redColor];
Class2 *objectB = [[Class2 alloc] init];
objectA.myColor = [UIColor redColor];
Class3 *objectC = [[Class3 alloc] init];
objectA.myColor = [UIColor redColor];
... etc.
Now I need, for example, to create a method that can change the color of a given object, whatever class it represents.
A typical method would be
- (void) changeColor:(Class1*) myOBJ toColor:(UIColor*)myColor {
myOBJ.color = myColor;
}
when in fact I need this
- (void) changeColor:(???) myOBJ toColor:(UIColor*)myColor {
myOBJ.color = myColor;
}
// what to put on ??? to make it generic? Is this a "whatever" kind?
thanks
EDIT
the problem of using this approach
- (void) changeColor:(id)myOBJ toColor:(UIColor*)myColor {
if ([myOBJ respondsToSelector:#selector(setColor:)]) {
myOBJ.color = myColor;
}
}
is this. Imagine I want to set the frame of the object.
Then I will have to have this:
- (void) changeColor:(id)myOBJ newFrame:(CGRect)myFrame {
if ([umID isKindOfClass:[Class1 class]]) {
Class1 *oneObj = (Class1 *)myObj;
oneObj.frame = myFrame;
}
if ([umID isKindOfClass:[Class2 class]])
Class2 *oneObj = (Class2 *)myObj;
oneObj.frame = myFrame;
}
if ([umID isKindOfClass:[Class3 class]])
Class3 *oneObj = (Class3 *)myObj;
oneObj.frame = myFrame;
}
}
in other words, I will have to repeat the same stuff 3 times... right?
in other words, the problem is not solved as this is the same of having 3 methods, one for each class.
Maybe you can use protocols? Make Class1, Class2 and Class3 conform to a protocol with a property myColor. Then you could have a method like this (assuming your classes are of type UIView and your protocol is called ColorProtocol):
- (void) changeColor:(UIView<ColorProtocol>*) myOBJ toColor:(UIColor*)myColor {
myOBJ.color = myColor;
myOBJ.frame = ...;
}
Here is what your protocol definition could look like:
#protocol ColorProtocol
#property (nonatomic, retain) UIColor *myColor;
#end
Change your class definition files (.h) as follows to specify that you will conform to the protocol:
interface Class1 : UIView <ColorProtocol> {...}
In the implementation files (.m) you must simply synthesize the myColor property to conform to the ColorProtocol:
#synthesize myColor;
If your classes are very similar, using inheritance might be even simpler though. Check out Philip Regan's answer.
You have a couple options. The simplest, and "most dangerous" approach is to use a type id. This will let you pass in any object, but you'll want to test that it actually has a color property before you try and set it.
- (void) changeColor:(id)myOBJ toColor:(UIColor*)myColor {
if ([myOBJ respondsToSelector:#selector(setColor:)]) {
myOBJ.color = myColor;
}
}
(That said, with the responds to selector check, this approach isn't all that dangerous, and it's much more flexible than the next idea.)
Another approach is to have all your objects inherit from a shared base class that has a color property. Then your parameter type would be the base class. This approach could be considered "safer" as the compiler would check that you're passing in the correct type of object. This approach also requires considerably more code.
If you want to use the first approach, but set something other than color, adjust the respondsToSelector: call appropriately.
- (void) changeFrame:(id)myOBJ newFrame:(CGRect)myFrame {
if ([myOBJ respondsToSelector:#selector(setFrame:)]) {
myOBJ.frame = myFrame;
}
}
In general, if you want to know if an object supports propertyX, use [myOBJ respondsToSelector:#selector(setPropertyX:)]. If the passed in object is declared as id, you can then call [myOBJ setPropertyX:newPropertyValue] or myObj.propertyX = newPropertyValue.
If you have multiple classes that share characteristics, then, if at all possible, I suggest refactoring the class structure so that those characteristics are contained in an umbrella parent class, we'll call it ClassZ. ClassZ's subclasses can override things as needed. Otherwise, let the method in the parent class handle it for you. Then, your method turns back into this...
- (void) changeColor:(ClassZ *) myOBJ toColor:(UIColor*)myColor {
myOBJ.color = myColor; // note, myObj is ClassZ, not the subclasses.
}
Otherwise, you are stuck with id and testing the individual classes.
use [object setFrame:newFrame]; instead of object.frame = newFrame;
and instead of oldFrame = object.frame; use oldFrame = [object frame];
??? will be 'id'.