So this one has me stumped - probably something simple, but I'm clueless.
I'm defining a custom class, containing one method that receives one message (an integer). When calling that method, the compiler refuses to recognize the message I'm trying to send along with the call. ("No known class method for selector 'sendMessage:'. Removing the message from both the call and the definition - i.e. removing the :(int)mode from the definition, and the :1 from the call - allows it to compile fine (but then of course I lose the functionality).
I've tried defining it as an instance method, and as a class method - neither one works.
Many thanks in advance for your collective wisdom!
custom class "Communications.h":
#interface Communications : NSString
+(NSString*)sendMessage:(int)mode;
#end
Communications.m:
#import "Communications.h"
#interface Communications ()
#end
#implementation Communications
+(NSString*)sendMessage:(int)mode {
// Do something important
}
ViewController.h:
#import "Communications.h"
- (void) tapPanic:(UITapGestureRecognizer*)sender;
ViewController.m:
- (void) tapPanic:(UITapGestureRecognizer *)sender {
[Animations animatePanic:self.view type:0];
panicactive = 1;
NSString* tmpResponse = [Communications sendMessage:1];
UILabel* tmpServerResponsePanic = [self.view viewWithTag:10002];
tmpServerResponsePanic.text = tmpResponse;
[[self serverResponsePanic] setNeedsDisplay];
}
So, chalk it up to weirdness with Xcode... copy / pasting the contents of Communications .h and .m into new files, with a new class definition (Comms), did the trick. I think the compiler got confused and was remembering an old definition of the method.
Related
I'm using #implementation to add a new function to UIView.
#implementation UIView (test)
- (void)newFunction {
}
#end
Now, in the newFunction I want to "grab" the object (UIView) that was used when calling the function.
For example when I call newFunction within viewDidLoad
- (void)viewDidLoad {
[myView newFunction];
}
I want the newFunction to know what object was used to make the call (in this case, myView).
A simple solution would be to pass it along when making the call ([myView newFunction:myView]), but that is not what I am looking for.
I looked at Apple's documentation on the subject, but didn't really find an answer to my question.
#import "UIView+UIView_Category.h"
#implementation UIView (UIView_Category)
- (void)newFunction
{
NSLog(#"Object = %#",self);
}
#end
What you describe is called a category (not #implementation). It is an extension to the UIView class (in this case).
Generalcally:
#implementation __CLASS_TO_EXTEND__ (__CATEGORY_NAME__)
The category, as it is an extension, is the instance that you call the method on. So, you use self as you usually would to access the current instance.
I am using AFNetworking, I have a subclass created for AFHTTPSessionManager which works on iOS7, i would like to know it is possible that i can inherit the same subclass but with a different super class say AFHTTPRequestOperationManager based on some preprocessor directives.
Thanks
The "standard" way to deal with this would be to define an interface for your class functions, then create "old" and "new" classes to implement the interface. Use a "factory" to create the correct one for the runtime environment.
You could instead use a "wrapper" class instead of the interface -- one that creates the version-specific class internally and forwards calls to it.
Applying the use of a Factory (in the form of a class cluster)
note that code below is only an indication, it won't compile from a copy/paste
#interface MyHTTPClient
- (void) post:(NSURLRequest *)request params:(NSDictionary *)params
#end
#implementation MyHTTPClient
- (id) init {
if(iOS_version < 7) {
return [[_MyiOS7HttpClient] alloc] init];
} else {
return [[_MyiOS6HttpClient alloc] init];
}
}
- (void) post:(NSURLRequest *)request params:(NSDictionary *)params {
NSAssert(NO, #"private instances should respond to this");
}
#end
now the private instances, which are not visible from the project (only via MyHttpClient)
#import "MyHttpClient.h"
#implementation _MyiOS7HttpClient
- (void) post:(NSURLRequest *)request params:(NSDictionary *)params {
// use new ios7 session manager here to do stuff
}
#end
and create a similar class for MyiOS6HttpClient which uses none of the iOS7 Session management.
So the Class Cluster in this case gives you:
A Clean interface to either MyiOS7HttpClient or MyIos6HttpClient via MyHttpClient,
Other code does not need to know which instance you are actually using.
No Need for message forwarding.
You can't do this at compile-time. The compiler has no idea which of the supported iOS version(s) your app will run on. You may create several versions of the class, and create the correct one based on a runtime version check.
Im trying to make it so that every single UIControl in my application (UIButton, UISlider, etc) all have special extra properties that I add to them.
I tried to accomplish this by creating a UIControl Category and importing it where needed but I have issues.
Here is my code.
My setSpecialproperty method gets called but it seems to be getting called in an infinite loop until the app crashes.
Can you tell me what Im doing wrong or suggest a smarter way to add a property to all of my UIControls?
#interface UIControl (MyControl)
{
}
#property(nonatomic,strong) MySpecialProperty *specialproperty;
-(void)setSpecialproperty:(MySpecialProperty*)param;
#end
////////
#import "UIControl+MyControl.h"
#implementation UIControl (MyControl)
-(void)setSpecialproperty:(MySpecialProperty*)param
{
self.specialproperty=param;
}
///////////////
#import "UIControl+MyControl.h"
#implementation ViewController
UIButton *abutton=[UIButton buttonWithType:UIButtonTypeCustom];
MySpecialProperty *prop=[MySpecialProperty alloc]init];
[abutton setSpecialproperty:prop];
While you can't add an iVar to UIControl via a category, you can add Associated Objects, which can be used to perform much the same function.
So, create a category on UIControl like this:
static char kControlNameKey;
- (void) setControlName: (NSString *) name
{
objc_setAssociatedObject(self, &kControlNameKey, name, OBJC_ASSOCIATION_COPY);
}
- (NSString *) controlName
{
return (NSString *)objc_getAssociatedObject(array, &kControlNameKey);
}
There's more to it than that, I guess you'll need to check if an association exists before setting a new one, otherwise it will leak, but this should give you a start.
See the Apple Docs for more details
self.specialproperty=param is exactly the same as calling [self setSpecialproperty] (see here for some totally non biased coverage of Obj-C dot notation), which makes your current usage infinitely recursive.
What you actually want to do is:
-(void)setSpecialproperty:(MySpecialProperty*)param
{
_specialproperty = param;
}
Where _specialproperty is the implicitly created ivar for your property.
I'm assuming there's some reason why you've implemented your setSpecialproperty setter? Why not just use the one that is implicitly created for you?
the problem is that you can not add a property to a category, you can add behavior (methods) but not properties or attributes, this can only be done to extensions, and you can not create extensions of the SDK classes
use your method as
change your method name to
-(void)setSpecialproperty:(MySpecialProperty *)specialproperty
-(void)setSpecialproperty:(MySpecialProperty*)specialproperty
{
if(_specialproperty!=specialproperty)
_specialproperty = specialproperty;
}
and synthesize your specialProperty as
#synthesize specialproperty=_specialproperty;
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
First off, I am using the game engine LevelHelper.
Does anyone know the proper way to access an instanced LevelHelper helper class from another class?
For example:
I have my main gameLayer class and a hudLayer class. The hudLayer class is being imported and instanced in the gameLayer class. However i need to be able to access and manipulate the sprites that are loaded in the hudLayer class with gameLayer class.
I was recommended to use the LevelHelper helper instance method. So i create the instance method inside of my hudLayer class, and then call it inside of my init method to load the sprites. I tried using this method as an instance method and i get an error saying unrecognized selector
+[hudLayer hudLoader];
If i try using the method as a class method i get an EXC_BAD_ACCESS Error.
I cant seem to find a solution.
My code:
hudLayer.h :
+(LevelHelperLoader*)hudLoader;
hudLayer.mm :
+(LevelHelperLoader*)hudLoader
{
LevelHelperLoader* lh;
finishScreen = [lh spriteWithUniqueName:#"finishScreen"];
return lh;
}
gameLayer.h :
LHSprite* finishScreen;
gameLayer.mm :
#import hudLayer.h
-(id) init {
[self retrieveRequiredObjects];
}
-(void) retrieveRequiredObjects {
finishScreen = [[hudLayer hudLoader] spriteWithUniqueName:#"finishScreen"];
NSAssert(finishScreen!=nil, #"Couldn't find the menu!");
}
Note: This code is just to make sure my logic and implementation of this is correct.
Any help is appreciated, thanks.
Have you tried stepping through your code in the debugger to find exactly which line causes the crash?
To me it looks as if it is here:
LevelHelperLoader* lh;
finishScreen = [lh spriteWithUniqueName:#"finishScreen"];
You have declared 1h, but you haven't created it. So you are sending a message to a non-existent object.
At very least, something like
LevelHelperLoader* lh = [[LevelHelperLoader alloc] init];
would help.
A cursory glance at the documentation adds more detail:
LevelHelperLoader* loader = [[LevelHelperLoader alloc] initWithContentOfFile:#"level1"];
In the docs, this is an instance variable - which suggests that hudLoader should be an instance method, not a class method:
- (LevelHelperLoader*) hudLoader;
and you should create your LevelHelperLoader* instance in your hudLoader initialiser.
update
You say in your comment:
inside of my init method for hudLayer.mm i call
lh = [[LevelHelperLoader alloc] initWithContentOfFile:#"level1"];
and in the .h i have
LevelHelperLoader* lh;
I am not sure if this is modifications since reading my answer or not. However here are some more thoughts.
Firstly can you sort out your naming conventions. Classes should start with Capitals.
HudLayer.h
Let's declare this lh instance variable as a property in your #interface and improve it's name:
#property (strong) LevelHelperLoader* levelHelper
HudLayer.mm
Allow it to be auto-synthesized or synthesize in your #implementation as:
#synthesize levelHelper = _levelHelper;
Then in your init method
_levelHelper = [[LevelHelperLoader alloc] initWithContentOfFile:#"level1"];
and hudLoader becomes
-(LevelHelperLoader*)hudLoader
{
finishScreen = [self.levelHelper spriteWithUniqueName:#"finishScreen"];
return self.levelHelper;
}
but then ask yourself, what is -hudLoader actually doing? The line that assigns to finishscreen? Is finishscreen an iVar? Do you need it? Perhaps not. Aside from that, all -hudLoader is doing is returning your already-created instance of LevelHelperLoader. Now that your iVar is a property you can access this from gameLayer using dot-notation property syntax, and remove hudLoader altogether:
GameLayer.h
#interface
#property (strong) Hudlayer* hudLayer;
#end
GameLayer.m
-(id) init {
_hudLayer = [[Hudlayer alloc] init];
[self retrieveRequiredObjects];
}
-(void) retrieveRequiredObjects {
finishScreen = [self.hudLayer.levelHelper spriteWithUniqueName:#"finishScreen"];
NSAssert(finishScreen!=nil, #"Couldn't find the menu!");
}
This makes me wonder whether you need a hudLayer class at all (maybe it is doing other useful work)... it looks as if you can get at your levelHelper directly from gameLayer.
GameLayer.h
#interface
#property (strong) LevelHelperLoader* levelHelper;
#end
GameLayer.m
-(id) init {
_levelHelper = [[LevelHelperLoader alloc] initWithContentOfFile:#"level1"];
[self retrieveRequiredObjects];
}
-(void) retrieveRequiredObjects {
finishScreen = [self.levelHelper spriteWithUniqueName:#"finishScreen"];
NSAssert(finishScreen!=nil, #"Couldn't find the menu!");
}
To conclude, I am not suggesting you follow this code line-for-line because I have no idea the broader context of your project. But you do need to sort out your confusion between classes and instances, allocation, instantiation, local vs instance variables. Please take care with naming conventions so that you know when you are sending a message to a Class or an instance of that class, and you know when you are addressing an iVar _directly or via a #property (eg self.property). Be consistent. And think about what a class is actually doing for you.
I want' to implement "Fix and continue functionality" that was in Xcode 3.
CONTEXT:
The main idea is:
When I need to "Fix something fast", I'm not re-compiling, project. I'm compiling small Attacker class with 'updated' method implementation, loading it into memory and replacing VictimClass's method which have incorrect implementation in runtime.
I think that this method will work faster that full project recompilation.
When i'm done with fixes i'm just copying source of Attacker class method to Victim class.
PROBLEM
At the moment, I don't know how correctly call [super ...] in Attacker class.
For example, i have VictimClass
#interface VictimClass : UIView #end
#implementation VictimClass
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
}
#end
#interface AttackerClass : NSObject #end
#implementation AttackerClass
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
[self setupPrettyBackground];
}
#end
....
// EXCHANGE IMPLEMENTATIONS
Method m = class_getInstanceMethod([AttackerClass class], #selector(drawRect:));
const char * types = method_getTypeEncoding(m);
IMP attackerImp = method_getImplementation(m);
class_replaceMethod([VictimClass class], #selector(drawRect:), attackerImp, types);
// Invoking drawRect on Victim
VictimClass * view = /* */;
[view setNeedsDisplay];
At this point , when drawRect: method will be called, this will lead to exception, since drawRect: will be called on NSObject class, but not on UIView class
So, my question is, how correctly call [super drawRect:] in AttackerClass, to have possibility to correctly exchange implementation in runtime?
Main idea is to provide a way to correctly replace any method in Victim class by Attacker's class method. Generally, you don't know, superclass of Victim class.
UPDATE: Replacing implementation code added.
You will have to
get the receivers class (e.g. with object_getClass(rcv))
then get the super class of it (with class_getSuperclass(class))
then get the implementation of it (with class_getMethodImplementation(superclass, sel))
then call the imp.
done
Stop at any step if you got nil or NULL.
Oh, and all this seems silly. But I assume that the question just lacks of context to see the motivation for such a hack.
[Update]
An explanation for future readers:
The super keyword is resolved at compile time. Therefore it does not the intended thing when changing methods at runtime. A method which is intended to be injected in some object (and its class hierarchy) at runtime has to do super calls via runtime as outlined above.
Assuming that the runtime changes you're making involve modifying the superclass, you'll have to do something like this:
#implementation AttackerClass
-(void) drawRect:(CGRect)rect
{
if( [super respondsToSelector:#selector(drawRect:)] )
{
[super drawRect:rect];
}
[self setupPrettyBackground];
}
#end
This will check if the superclass "knows about" drawRect:, and doesn't call it in the case that super has no drawRect: selector.
Hence, when the superclass is NSObject the drawRect: message will not be sent. When you change it to UIView at runtime (whatever your reason for that is), the message can safely be sent.
One approach is to use objc_msgSendSuper. Your method -[AttackerClass drawRect:] will have the following implementation:
- (void)drawRect:(CGRect)rect {
struct objc_super superTarget;
superTarget.receiver = self;
superTarget.class = object_getClass(self);
objc_msgSendSuper(&superTarget, #selector(drawRect:), rect);
[self setupPrettyBackground];
}
but why do you need to call draw rect method for superclass NSObject, when NSObject hasn't got that method? just don't do it... call it just in VictimClass drawrect