instantiate class method issue while trying to resize and image - ios

I am quite new to iOS development and its my first time trying to resize and image and dealing with class methods.
I am following this post on how to resize an image. I placed the + (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize; in selectExerciseImageViewController.h and copied the relevant code to selectExerciseImageViewController.m.
Then trying to instantiate the class using
selectExerciseImageViewController * newC = [[selectExerciseImageViewController alloc] init];
UIImage* newImage = [newC imageWithImage:[info objectForKey:#"UIImagePickerControllerOriginalImage"]
scaledToSizeWithSameAspectRatio:CGSizeMake(40.0,40.0)];
but its throwing an error saying that there is not visible interface for that method. i tried putting self instead of newC but still throws the same error.
I would appreciate some guidance on why its behaving like this.

Your
+ (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize;
method is a class method and you are trying to invoke it on an instance of selectExerciseImageViewController. Try:
[selectExerciseImageViewController imageWithImage:[info objectForKey:#"UIImagePickerControllerOriginalImage"]
scaledToSizeWithSameAspectRatio:CGSizeMake(40.0,40.0)];
or you can declare your method as an instance method, just change the + sign (class method) to a - sign (instance method)
- (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize;

Related

Calling a instance method while using childNodeWithName

Is it possible to call an instance method without using an instance variable or #property?
Here is how I create an instance of a class. Within the method, I try to call on the class's instance movement method to force the instance to move:
-(void)createCharacterNPC
{
int randomness = [self getRandomNumberBetweenMin:1 andMax:20];
for (int i = 0; i < randomness; i += 1)
{
NSString *npcName = [NSString stringWithFormat:#"anNPC%i", randomness];
NPCclass *NPC = [[NPCclass alloc] initWithName:npcName];
NPC.position = CGPointMake(self.size.width/2, self.size.height/2);
NPC.zPosition = 1.0;
[_worldNode addChild:NPC];
// THIS OBVIOUSLY WORKS. But I can't use this technique outside this method.
[NPC beginMovement];
// THIS IS WHAT I WANT, BUT XCODE DOESN'T ALLOW ME TO WRITE CODE THIS WAY.
[[_worldNode childNodeWithName:#"anNPC1"] beginMovement];
}
}
Is there a way to allow [[_worldNode childNodeWithName:#"anNPC1"] beginMovement]; to work? Or some way similar to this so I wouldn't have to have create an instance variable of NPC (like so: _NPC)?
I'm asking because all of this is happening inside a mini-game scene and NPCclass will be initialized a random number amount of times (with arc4random() method). NPCclass moves on its own using vector (physics in a platformer) movement but I need to initialize its movement method right after creation then I need to periodically access each individually created instance of NPCclass using its name in other methods of the scene. Since I don't know how many NPCclass instances will be created each time the mini-game is played, I CAN'T use IVAR's or something like #property NPCclass *anNPC;
Please help.
Xcode complains about
[[_worldNode childNodeWithName:#"anNPC1"] beginMovement];
because the method -childNodeWithName returns an SKNode object. Instances of the SKNode class do not respond to the selector -beginMovement (or as Xcode puts it, no visible #interface declares the selector -beginMovement). Xcode shows this to you to force you to make sure you wrote what you wanted to write. Since you are sure, you can tell Xcode that the returned object is of the type NPCclass.
(NPCclass *)[_worldNode childNodeWithName:#"anNPC1"]
Now you can expand the statement to call -beginMovement.
[(NPCclass *)[_worldNode childNodeWithName:#"anNPC1"] beginMovement];
Note
There are a few concepts which you might be confusing. NPCclass is a class. +node is a class method of SKNode, which you can call with [NPCclass node];. -beginMovement is an instance method, called with:
NPCclass *npc = [NPCclass node];
[npc beginMovement];
Or:
[(NPCclass *)anyObject beginMovement];
// make sure anyObject responds to this selector though, or you app will crash.
Class methods are prefixed with a +, instance methods with -.
Class methods do not use an instance, just the class name.
As an example consider the
NSString` class method: `+ (id nullable)stringWithContentsOfFile:(NSString * nonnull)path
and a usage:
NSString *fileData = [NSString stringWithContentsOfFile:filePath];

What is the -(CGRect *)frame method in iOS?

Codes:
if (!CGRectContainsPoint([[viewArray objectAtIndex:0] frame], CGPointMake(newX, newY)) )
{
....
}
Question
I wanna to get a "frame" value of a UIView in a view array, so i used this:
((UIView *)[viewArray objectAtIndex:0]).frame
I utilize (UIView *) to compulsively convert an id object to UIView, otherwise it will trigger error like "Property 'frame' not found on object of type 'id'". But the method below seems successfully escape from this error:
[[viewArray objectAtIndex:0] frame]
So [id frame] can Automatically detect the id's real type and then make it to call the method?
I really wanna to know methods like
[id frame]----id's real type is UIView
[id view ]----id's real type is UIViewController
Are these methods getter methods or setter methods? I cannot tell the diffrence and the apple document show them like :
#property(nonatomic) CGRect frame
Thx a lot for your help!
The method called in the end is -(CGRect)frame;. Using the dot syntax is just a syntactic sugar the objective-c compiler provides. For this sugar to work, the compiler needs to know the type of the object it uses.
On the other end, objective-c uses message passing for calling methods. Which means that when you use the syntax [id message], it will try to execute the selector #selector(message) on id. id being a special type denoting any object in the runtime, it accepts every selector and will throw an unknown selector exception at runtime if the object cannot execute it.
By defining a property like: #property(nonatomic) CGRect frame the property works as both a getter and setter.
For example, to modify the width of a frame, you might write:
CGRect frame = myView.frame;
frame.size.width = 100;
myView.frame = frame;
For a good description of dot notation, see this fine answer.

How should CategoryA override categoryB method

In AFNetworking 2.0, in UIImageView+AFNetworking there is a method:
+ (id <AFImageCache>)sharedImageCache
I want to override it and return here my custom object. I'd like also to override all the methods in AFImageCache, so basically I'd make a new protocol here. I've thought about method swizzling, however because lack of experience I'm not sure if it works ok with 2 categories. What if my category loads before AFNetworking category, will it still be working?
At all, is this approach a good one? I want to add disc caching to the memory one and I wonder which way is the cleanest one in terms of code quality.
Do not use Categories to override a method. Per the documentation
"If the name of a method declared in a category is the same as a
method in the original class, or a method in another category on
the same class (or even a superclass), the behavior is undefined
as to which method implementation is used at runtime. "
refer to the documentation at "Avoid Category Method Name Clashes" -->
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/ProgrammingWithObjectiveC.pdf
Subclass and override the method instead and use the subclass?
Analyzing your scenario, It make sense to do method swizzling.
Note: Make sure yourCache will behave the same way as sharedImageCache, else it will result in crash.
#implementation UIImageView (Swizzling)
+ (void)load {
static dispatch_once_t token;
dispatch_once(&token, ^{
Class myClass = [self class];
Method originalMethod = class_getInstanceMethod(myClass, #selector(sharedImageCache));
Method newMethod = class_getInstanceMethod(myClass, #selector(NewSharedImageCache:));
method_exchangeImplementations(originalMethod, newMethod);
});
}
//This is just for sample. you can create your buffer in your own way
static id <yourCache> yourBuffer;
+ (id <yourCache>)NewSharedImageCache
{
return yourBuffer;
}
#end

UIImageView not displaying new image

I have an image cache class, which downloads icons if necessary and caches them. In my view controller, in viewDidAppear, I have:
// (showIcon is a UIImageView from the storyboard)
showIcon.image = [[LRImageCache imageCache] imageForURL:iconURL completionTarget:self action:#selector(updateImage:)];
If the image is already cached, it is returned here, and is correctly displayed. Otherwise, a placeholder image is returned, and the cache class attempts to download the image. When (if) successful, it calls the target/action:
- (void)updateImage:(UIImage *)image
{
showIcon.image = image;
}
Setting a breakpoint on that line confirms that 'image' is the correct, downloaded image - but it doesn't display!
I can't help but think I'm missing something really obvious...
You are calling the updateImage: which is expecting an argument, with your code you call the method but you don't provide the argument.
Consider creating an image object first like so:
UIImage *myImage = [[LRImageCache imageCache] imageForURL:iconURL completionTarget:self action:#selector(updateImage)];
Remove the argument from the updateImage method (remember to remove the colon from the selector when setting the image.
- (void)updateImage{
showIcon.image = myImage;
}

How to override method of

There is a class alpha which has method -(void)doSomething. There is also a class beta which I've created and can modify as I need. Instance of alpha can only be created by calling [gamma createAlpha].
What I need is to make class beta to inherit alpha and override doSomething while I still have to create instances of alpha via calling [gamma createAlpha].
Is there any way to implement this?
I hope my question makes sense.
Thank you!
Yes. You can use method swizzling. You will need to create category with following code:
#implementation alpha (newDoSomething)
// This is called when the category is being added
+ (void) load {
Method method1 = class_getInstanceMethod(self, #selector(doSomething));
Method method2 = class_getInstanceMethod(self, #selector(swizzleddoSomething));
// this is what switches the two methods
method_exchangeImplementations(method1, method2);
}
- (void)swizzleddoSomething
{
... your code
//You can call super implementation here with following line
//[self swizzleddoSomething];
}
#end
You will still have class alpha. It will be successfully created by [gamma createAlpha], but it will have your implementation of doSomething method.

Resources