Can not call a helper function from another function - objective-c

I have written a helper function
-(NSString*) rotatePattern: (NSString*) patternToRotate
{
int tempIndex = indexOfChar(patternToRotate,_SignatureChar);
if(tempIndex != 0)
{
NSString* secondPartString = [patternToRotate substringToIndex:tempIndex-1];
NSString* firstPartString = [patternToRotate substringFromIndex:tempIndex];
NSMutableString *finalString;
[finalString setString:#""];
[finalString appendString:firstPartString];
[finalString appendString:secondPartString];
return finalString;
}
return patternToRotate;
}
Now I trying to call this function from another static method using below three method it is giving me used of undeclared identifier rotatePattern or use of undeclared identifier self
_finalPattern = [rotatePattern: #"hello"];
OR
_finalPattern = [self rotatePattern: #"hello"];
OR
_finalPattern = [self.rotatePattern: #"hello"];

If you can, make rotatePattern a static method, then you can use it like
[self rotatePattern: #"hello"]; if its within the same class
or [ThatClassName rotatePattern: #"hello"]; if its called from another class (or this class, this is the more politically correct way to do it)
otherwise if you cant make this method static, you can try make the other one non-static.
if both of those are an issue, what you are trying to do is not possible, since calling an instance method without an instance of the class doesnt make sense.

Related

Call a NSDictionary Value as Method

How can I can I call a function which name I stored as a value an an NSDictionary? Basically I need to typecast a String as a method name/call. Is this possible?
[thisCellContent objectForKey:#"callFunction"] //the object contains the function name to be called
//call this value as function, something similar to this ..
[self [thisCellContent objectForKey:#"callFunction"]]
Is something like this possible?
Not like this, but you can use the runtime/reflection:
NSString *s = [thisCellContent objectForKey:#"callFunction"];
SEL sel = NSSelectorFromString(s);
[self performSelector:sel withObject:nil];
I would suggest putting an Objective-C block into the dictionary. You can then call the block (and it can call other things if you like). Something like this:
//In code that sets up the dictionary
void (^thingToCall)() = [^{ /* any code you want to run here */ } copy];
[dictionary setObject:thingToCall forKey:#"callFunction"];
//In code that uses the dictionary
void (^thingToCall)() = [dictionary objectForKey:#"callFunction"];
thingToCall(); //call the block

Objective-C dynamic properties at runtime?

Is it possible to create an Objective-C class that can have an arbitrary number of dynamic properties at runtime?
I want to be able to call mySpecialClass.anyProperty and intercept this inside my class to be able to provide my own custom implementation that can then return an NSString (for instance) at runtime with raising an exception. Obviously this all has to compile.
Ideal would be if I could refer to my properties using something similar to the new literal syntax, e.g. mySpecialClass["anyProperty"].
I guess in a way I want to create something like a dynamic NSDictionary with no CFDictionary backing store, that executes 2 custom methods on property getting and setting respectively, with the property name passed in to these accessor methods so they can decide what to do.
There are at least two ways to do this.
Subscripting
Use objectForKeyedSubscript: and setObject:forKeyedSubscript:
#property (nonatomic,strong) NSMutableDictionary *properties;
- (id)objectForKeyedSubscript:(id)key {
return [[self properties] valueForKey:[NSString stringWithFormat:#"%#",key]];
}
- (void)setObject:(id)object forKeyedSubscript:(id <NSCopying>)key {
[[self properties] setValue:object forKey:[NSString stringWithFormat:#"%#",key]];
}
Person *p = [Person new];
p[#"name"] = #"Jon";
NSLog(#"%#",p[#"name"]);
resolveInstanceMethod:
This is the objc_sendMsg executed by the runtime for all methods:
If you look at the bottom, you have the opportunity to resolveInstanceMethod:, which lets you redirect the method call to one of your choosing. To answer your question, you need to write a generic getter and setter that looks-up a value on a dictionary ivar:
// generic getter
static id propertyIMP(id self, SEL _cmd) {
return [[self properties] valueForKey:NSStringFromSelector(_cmd)];
}
// generic setter
static void setPropertyIMP(id self, SEL _cmd, id aValue) {
id value = [aValue copy];
NSMutableString *key = [NSStringFromSelector(_cmd) mutableCopy];
// delete "set" and ":" and lowercase first letter
[key deleteCharactersInRange:NSMakeRange(0, 3)];
[key deleteCharactersInRange:NSMakeRange([key length] - 1, 1)];
NSString *firstChar = [key substringToIndex:1];
[key replaceCharactersInRange:NSMakeRange(0, 1) withString:[firstChar lowercaseString]];
[[self properties] setValue:value forKey:key];
}
And then implement resolveInstanceMethod: to add the requested method to the class.
+ (BOOL)resolveInstanceMethod:(SEL)aSEL {
if ([NSStringFromSelector(aSEL) hasPrefix:#"set"]) {
class_addMethod([self class], aSEL, (IMP)setPropertyIMP, "v#:#");
} else {
class_addMethod([self class], aSEL,(IMP)propertyIMP, "##:");
}
return YES;
}
You could also do it returning a NSMethodSignature for the method, which is then wrapped in a NSInvocation and passed to forwardInvocation:, but adding the method is faster.
Here is a gist that runs in CodeRunner. It doesn't handle myClass["anyProperty"] calls.
You're asking different things. If you want to be able to use the bracket syntax mySpecialClass[#"anyProperty"] on instances of your class, it is very easy. Just implement the methods:
- (id)objectForKeyedSubscript:(id)key
{
return ###something based on the key argument###
}
- (void)setObject:(id)object forKeyedSubscript:(id <NSCopying>)key
{
###set something with object based on key####
}
It will be called everytime you use the bracket syntax in your source code.
Otherwise if you want to create properties at runtime, there are different ways to proceed, take a look at NSObject's forwardInvocation: method, or look at the Objective-C Runtime Reference for functions to dynamically alter a class...
Guillaume is right. forwardInvocation: is the way to go. This answer gives some more details: method_missing-like functionality in objective-c (i.e. dynamic delegation at run time)
This has even more details: Equivalent of Ruby method_missing in Objective C / iOS
And these are some other lesser known Obj-C features that might help you: Hidden features of Objective-C
Enjoy!

When do you use a dot after self

To my understand self refers to the current class and when i use a dot after self is to use one of its properties. In the code here there's a use in self.popOperand that i don't understand if popOpernad is not a property. Another thing i don't understand is why
[self pushOperand:result]; works and [self.pushOperand:result]; doesn't.
#import "Calcbrain.h"
#interface Calcbrain()
#property (nonatomic,strong) NSMutableArray *operandStack;
#end
#implementation Calcbrain
#synthesize operandStack = _operandStack;
-(NSMutableArray *) operandStack
{
if(_operandStack == nil) _operandStack = [[NSMutableArray alloc]init];
return _operandStack;
}
-(double)popOperand
{
NSNumber *objectNum = [self.operandStack lastObject];
if (objectNum)[self.operandStack removeLastObject];
return [objectNum doubleValue];
}
/*-(void) setOperandStack:(NSMutableArray *)operandStack
{
_operandStack = operandStack;
}*/
-(void)pushOperand:(double)opernand
{
[self.operandStack addObject:[NSNumber numberWithDouble:opernand]];
}
-(double)performOperation:(NSString *)operation
{
double result=0;
if([operation isEqualToString:#"+"])
{
result = self.popOperand + self.popOperand;
}
else if ([#"*" isEqualToString:operation])
{
result = self.popOperand * self.popOperand;
}
[self pushOperand:result];
return result;
}
#end
Whilst the . notation is primarily used for properties, it can be used for paramaterless methods that return a value. Why? Because the synthesised getter for a property is in the same form.
-(double)calcValue {
....
return value;
}
Is equivalent to the property declaration:
#property (nonatomic, readonly) double calcValue;
Whilst there may be no property declaration, it doesn't mean the . notation cannot be used. The compiler will effectively change . notation to a method call when compiling, as . is a form of syntactic sugar. As so:
self.popOperand
// Translates to
[self popOperand];
This leads on to part 2, why does [self.pushOperand:result]; not work? The reason being is that . does not support the passing of parameters directly.
The only way to assign/push a parameter to a property is via self.pushOperand = result, but this wouldn't work, because there isn't a corresponding - (void)setPushOperand:(double)pushOperand; that the . notation assignment maps to.
[self pushOperand:result]; works because you're being explicit in calling a particular method, called pushOperand:.
Overall, keep . notation for properties only, and if you're using a method that isn't designed to be a 'property', be explicit.
Update: self is a reserved keyword, that represents a pointer to the instance we're working within at that time.
For example, I can create two instances of Calcbrain outside of Calcbrain, for example BrainViewController:
Calcbrain* instance1;
Calcbrain* instance2;
Now, Calcbrain has methods declared within it, let's use -(double)performOperation:(NSString *)operation as an example. Now, if I wanted to call that from BrainViewController, I would do:
[instance1 performOperation:#"+"];
[instance2 performOperation:#"+"];
Because we are calling a method which is part of another class, I have to determine the correct instance I've created to refer to it (i.e. instance1 and instance2). But how would I call that from within the class itself, and make sure it applies to the correct instance? The instance I've created is unaware of the other instances I've created. Use self. self allows you to reference yourself within methods. So if I wanted to performOperation within Calcbrain itself, I would need to use self:
[self performOperation:#"+"];
The "dot" is just a syntactic sugar, it can be used even if there isn't a declared property. The expression
a.someProperty
is equivalent to
[a someProperty]
and the expression
a.someProperty = c
is equivalent to
[a setSomeProperty:c]
Therefore, self.popOperand is just the same as [self popOperand]. And one could also use the "dot" in some absurd cases like [NSMutableArray alloc].init.
Using the "dot" syntax for non-properties are highly discouraged. If I were the maintainer of this code I would change all self.popOperand back to [self popOperand] to avoid confusion.
(BTW, it is not defined which side of the + will get evaluated first. Better change
result = [self popOperand] + [self popOperand]
to
double operand1 = [self popOperand]
double operand2 = [self popOperand]
result = operand1 + operand2;
This will be a trouble when you define - and /.)
Dot is used to access properties of the class. You can also access properties and methods without dots:
[classInstance someMethodOrProperty];
This code: [classInstance someProperty]; equals this code classInstance.someProperty; You cannot call methods with dots like properties.

How to call my method in cocoa, self doesn't work

Working on a program that will record some things from the webcam when a user presses physical buttons connected to the mac via phidgets. Have call methods on other places in my app simply doing [self method: input], but on one place it doesn't work. What could be wrong?
This is the method i want to run if i get inputchange in my program.
Also i do -(void)reportButton2:(NSInteger)inputVal:(NSInteger)inputInd; in my .h file.
-(void)reportButton2:(NSInteger)inputVal:(NSInteger)inputInd {
//NSLog(#"phidget för port = %%d med signal %%d", ind, val);
if(inputVal == 1)
{
NSError* error;
NSFileManager* deleteMgr = [NSFileManager defaultManager];
NSString* path = #"/Users/Shared/tempFile.mov";
[deleteMgr removeItemAtPath:path error:&error];
[mCaptureMovieFileOutput recordToOutputFileURL:[NSURL fileURLWithPath:#"/Users/Shared/tempFile.mov"]];
}
else if(inputVal == 0)
{
[mCaptureMovieFileOutput recordToOutputFileURL:nil];
}
}
The code below give me result if imput from the buttons change. Here i just can't seem to call reportbutton2.
If i try to use [self reportButton2..] in gives me "Use of undeclared identifier 'self'"
int gotInputChange(CPhidgetInterfaceKitHandle phid, void *context, int ind, int val) {
what to do here?
return 0;
}
The problem is that gotInputChange is a C function not a Objective C method and so has no udea what self is as it does not belong to a class.
for [self reportButton2... = to work it needs to be a method in your class
I usually put something like this at the top of callbacks like gotInputChange:
MyObject *self = (id)context;
Then I can use self throughout the function as if it were a method.
The other thing being in a function makes harder is asserting conditions. The regular assertion macros, such as NSAssert and NSParameterAssert, require both of the implicit arguments to every method (self is one of them) to exist. In a C function, you must use NSCAssert, NSCParameterAssert, etc. instead.
You can also use your delegate.
SomeNameAppDelegate *delegate = (SomeNameAppDelegate *)[[NSApplication sharedApplication] delegate];
[delegate yourMethodName];
It works like in example if your target method in AppDelegate class. But when you have an access to delegate, you can create a pointers to necessary classes and use them over delegate.
Quickest but not soo nice way is to make your Class a singleton and access it from the gotInputChange function.
Okay thanks! Din't have any clue that it was C would never have solved it by myself. Did some googeling and this one did the trick for me.
[(id)context performSelectorOnMainThread:#selector(reportButton2:)withObject:[NSArray arrayWithObjects:[NSNumber numberWithInt:ind], [NSNumber numberWithInt:val], nil] waitUntilDone:NO];

Objective-C Bool Question

I am trying to see if a string has more than 6 characters in it. If it does it is not valid, and like wise for the other.
My problem is I am trying to call this method in a different method. I am not passing anything but instead I am using a NSString globally.
NSString *string = #"123456";
-(BOOL) isValid{
if ([string length] > 6) {
return YES;
}
else {
return NO;
}}
How do I call this function from another function without passing anything in the parameter?
If the methods are in the same class:
[self isValid];
otherwise:
[someObject isValid];
BOOL valid = [self isValid];
This is the most basic of calls in ObjC. You probably should be starting with a tutorial or book.