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.
Related
excuse me. I want to use block as my property in category to change my code style as follows, but there is something wrong and I don't know why.
Here is my code :
```
typedef NSString* (^MethodreplacingRangeWithString)(NSRange range,NSString * string);
typedef NSString* (^MethodAppend)(NSString *) ;
#interface NSString (Speech)
#property(nonatomic ,copy)MethodreplacingRangeWithString replacingRangeWithString ;
#property(nonatomic, copy)MethodAppend append ;
+(void)speech:(NSString *)content;
#end
#implementation NSString (Speech)
//setter and getter
static NSString * a = #"replacingRangeWithString" ;
-(void)setReplacingRangeWithString:(MethodreplacingRangeWithString)replacingRangeWithString{
objc_setAssociatedObject(self, #selector(replacingRangeWithString), replacingRangeWithString, OBJC_ASSOCIATION_RETAIN_NONATOMIC) ;
}
-(MethodreplacingRangeWithString)replacingRangeWithString{
return objc_getAssociatedObject(self, #selector(replacingRangeWithString)) ;
}
//setter and getter
static NSString * b = #"append" ;
-(void)setAppend:(MethodAppend)append{
objc_setAssociatedObject(self, #selector(append), append,OBJC_ASSOCIATION_RETAIN_NONATOMIC) ;
}
-(MethodAppend)append{
return objc_getAssociatedObject(self, #selector(append)) ;
}
//block
-(void)configureReplacingRangeWithStringProperty{
__weak typeof (self) weakSelf = self ;
self.replacingRangeWithString = ^(NSRange range,NSString * str){
return [weakSelf stringByReplacingCharactersInRange:range withString:str];
};
}
-(void)configureAppend{
__weak typeof (self)weakSelf = self ;
self.append = ^(NSString *str){
return [weakSelf stringByAppendingString:str] ;
};
}
to change the style as follows :
NSString * str = #"hello world" ;
[str configureAppend] ;
[str configureReplacingRangeWithStringProperty] ;
str = str.replacingRangeWithString(NSMakeRange(6, 5),#"iOS").append(#" hhhhh") ;
```
here is sth wrong with my configures and I don't know why
The cause of the actual crash you are getting is probably down to a misunderstanding of associated objects. When you associate an object you do so to a specific instance, not to all instances of the same type.
Looking at your code:
[str configureAppend] ;
[str configureReplacingRangeWithStringProperty] ;
At this point you have associated two objects with the particular instance that str is referring to. Now you try to do:
str = str.replacingRangeWithString(NSMakeRange(6, 5),#"iOS").append(#" hhhhh") ;
Breaking this up:
str.replacingRangeWithString
This invokes the property replacingRangeWithString on whatever object instance str is referencing. Let's call that object A. Now your previous two statements associated objects with A, so this works and you get your block reference back.
str.replacingRangeWithString(NSMakeRange(6, 5),#"iOS")
This invokes the block and returns a different string, call that object B.
str.replacingRangeWithString(NSMakeRange(6, 5),#"iOS").append
This invokes the property append on object B, you have associated no objects with object B so this returns a null reference.
str.replacingRangeWithString(NSMakeRange(6, 5),#"iOS").append(#" ahhhh")
You attempt to call your "block", but you have a null reference => memory fault.
Update
At this point I originally suggested that you need to rethink your design - you do - and that a solution might not be as simple as you might like - and since then it dawned on me that there might be a simple approach...
Provided you are just trying to replace method calls with property accesses so you can neatly chain calls together; i.e. that you've no intention of calling your configure... methods with blocks which perform different operations; then you can dynamically create and return a block in your property. Here is the outline for append. First make the property read only:
#property(nonatomic, readonly) MethodAppend append;
and then define it using:
-(MethodAppend)append
{
NSString *copied = self.copy;
return ^(NSString *string){ return [copied stringByAppendingString:string]; };
}
This first copies the string in case the instance it is called on is an NSMutableString, you don't know how long after this property is invoked that the block will be called and the string value could have been changed by that point. Then it returns a block which accepts the required arguments and calls the intended method.
That is all that is required, no setters or configure methods, and no associate objects.
HTH
You declare the properties as copy and then implement strong setters.
More likely than not, your crash is because you have a block on the stack that is being used after the stack frame is destroyed.
This question already has answers here:
Would it be beneficial to begin using instancetype instead of id?
(5 answers)
Closed 7 years ago.
I've just been reading and learning about instancetype and how in most cases it should be used instead of id in modern objective-c. Can I just ask when, then, would it be advisable to actually use id and not instancetype?
Thanks.
id
id is the generic type variable. Id doesn't warn us at compile time but it will crash if there is any problem.
Instancetype
instancetype does type checking for us at compile time to warn us of problems.
eg:
Animal.h
#interface Animal : NSObject
+ (id)giveMeAnimalA;
+ (instancetype)giveMeAnimalB;
+ (Animal *)giveMeAnimalC;
#end
Animal.m
#implementation Animal
+ (id)giveMeAnimalA {
return [[[self class] alloc] init];
}
+ (instancetype)giveMeAnimalB {
return [[[self class] alloc] init];
}
+ (Animal *)giveMeAnimalC {
return [[[self class] alloc] init];
}
#end
Suppose if we use [[Animal giveMeAnimalA] count];
The compiler will warn us of nothing, but we will crash at runtime with an exception because Animal doesn't have a count method.
And If we use [[Animal giveMeAnimalB] count];
The compiler would immediately warn us that Animal does not have a count method, and we could avoid crashing at runtime. But wouldn't it be simpler just to make our return type Animal* ?
Imagine we have a Dog subclass of Animal:
#interface Dog : Animal
- (void)makeSound;
#end
Now if we tried to call
[[Dog giveMeAnimalC] makeSound];
This wouldn't work because we would have been returned an Animal that doesn't have a makeSound method.
For complete last answer, i suggest you an example when Id is supported. It's on the ForIn Loop (fast enumeration)
Imagine, you have an array with three different objects like below :
NSArray *anotherArray = #[#"One element of Another Array",#"Second Element of Another Array"];
NSArray *array = #[#"First",#[anotherArray],#(12)];
for (id item in array)
{
if ([item isKindOfClass:[NSString class]])
{
NSLog(#"Im a NSString");
}
if ([item isKindOfClass:[NSArray class]])
{
NSLog(#"Im a NSArray");
}
if ([item isKindOfClass:[NSNumber class]])
{
NSLog(#"Im a NSNumber");
}
}
The id is a generic data type which can hold any type of data like nsstring,uiimage,nsarray and remaining all,so if you are having the requirements like returning the objects dynamically from a method you better use the return type of that method as id,hope you will get it
You can not use instancetype as return type when the type of the value that is returned is not known beforehand. If a method might return either an NSButton or an NSString depending on context, you can only use id.
instancetype is just a placeholder for the class that it is being used in; if a method of class Foo is like
- (instancetype) getMeFoo
then it is equivalent to
- (Foo *) getMeFoo
It can not return an NSString; the compiler would complain. However,
- (id) getMeFoo
can return any class type.
You could theoretically use a common superclass of the possibly returned types (for example, NSObject); but then you would need to typecast it when assigning to a concrete variable, or the compiler would bug you with warnings.
- (NSObject *) getMeFoo {
return #"foo!";
}
NSString *myString = (NSString *)[self getMeFoo];
The id type is "automatically" cast:
- (id) getMeFoo {
return #"foo!";
}
NSString *myString = [self getMeFoo];
But never forget to check if you really got the expected type:
NSString *myString = [self getMeFoo];
if (![myString isKindOfClass:[NSString class]]) {
// Danger, Will Robinson!
}
"I've just been reading and learning about instancetype and how in most cases it should be used instead of id in modern objective-c. Can I just ask when, then, would it be advisable to actually use id and not instancetype? Thanks."
You learned wrong. Kind of. The problem is that a language like Objective-C is complicated, and every rule will come with a long list of "do this IF a and b and c"... which you have to understand.
instancetype is used in one very particular situation: As the return type of init methods. You can't use for example UIButton* because an init method of UIButton could be used by a subclass, so the init method doesn't actually a UIButton but some subclass. That's why "id" was used which means "some object but I have no idea which object actually". "instancetype" on the other hand tells the compiler "you are clever, you figure it out. So with [[UIButton alloc] init] the compiler knows it returns UIButton*. [[MyButtonSubclass alloc] init] the compiler knows it returns MyButtonSubclass*.
In no other situation would you use instancetype.
Always give the compiler as much information as you can. If you have an object declared as UIButton* the compiler knows it's a UIButton or a subclass. If you have an object declared as id the compiler knows nothing. That means the compiler can't tell you if you do something stupid (like assigning a UIButton* to an NSString*, or calling the length method on a UIButton).
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!
am working my way through the "Beginning iPad Development" Apress book and have noticed that sometimes when the author is assigning values to a property they will use:
self.variable = value;
and other times, they will use:
variable = [value retain];
In both cases variable is a property defined as:
#property (nonatomic, retain) TYPE variable;
I wondered if anyone knew why this is done to help me better understand
Thanks,
William
One place where you use the second form is if you're defining your own setter method. You can't assign to self.variable there, because you'll call the setter recursively. So for example this is wrong:
-(void)setVariable:(TYPE*)value {
if (value != variable) {
[variable release];
self.variable = [value retain]; // WRONG! Calls
// [self setVariable:[value retain]]
}
}
This is right:
-(void)setVariable:(TYPE*)value {
if (value != variable) {
[variable release];
variable = [value retain];
}
}
Does that help?
They are often equivalent memory-wise. The compiler turns self.variable = value into [self setVariable:value] which then calls the generated setter (if you're using #synthesize) and retains it for you.
I'd like (at runtime) to bind a parameter to a function as you can do in boost::bind - a little like the following:
-(void)myFuncWithParameter:(NSString*)param {
NSLog(param);
}
-(void)init {
UIButton *helloButton = [UIButton buttonWithType:UIButtonTypeCustom];
[helloButton addTarget:self action:#selector(myFuncWithParameter:#"hello") forControlEvents:UIControlEventTouchUpInside];
}
So... I'm dynamically binding (at runtime) the value #"hello" to a parameter.
Obviously the above isn't the correct Syntax. Does anyone know if this is possible and the correct syntax?
Cheers,
Nick.
The short answer is no, or at least not at that level.
The long answer is that it is technically possible to build something akin to using NSInvocations (and/or forwardInvocation:), doing something clever in methodForSelector: and or by dynamically registering method implementations, but it is very tricky, especially if you care at all about speed.
If I had some code where building curried methods like that was really worthwhile, what I would do is something like this (written in this comment, untested);
//FIXME: In a real implementation you would do some mangling, this code will get confused if you have _s in the curried selector, and thus could be exploitable
//This method makes a unique selector by mangling the arguments
- (SEL) selectorForSelector:(SEL)bindSel withString:(NSString *)bindString {
NSString *mangle = [NSString *stringWithFormat:#"LGBind_%#_%#"], NSStringFromSelector(bindSel), bindString];
SEL retval = NSSelectorFromString(mangle);
//Register the imp. You probably want to check if it is already reg
if (![self respondsToSelector:retval]) {
class_addMethod([self class], retval, LGBind_IMP, "v#:")l
}
}
//Generic dispatcher imp
void LGBind_IMP(id self, SEL _cmd) {
NSString *selectorName = NSStringFromSelector(_cmd);
NSArray *array [selectorName componentsSeparatedByString:#"_"];
//Skip index 0; it is #"LGBind"
NSString *originalSelectorString = [array objectAtIndex:1];
NSString *originalArgString = [array objectAtIndex:2];
//Get our the SEL and the IMP
SEL originalSEL = NSSelectorFromString(originalSelectorString);
IMP originalIMP = [self methodForSelector:originalSEL];
//call the original imp
originalIMP([self class], originalSEL, originalArgString);
}
Obviously depending on your exact needs you could do things somewhere differently, for instance you could lazily by the imps in forwardInvocation, or stash data about the managled selector in a dict in the instance instead of just managling it into the selector name.
The general answer is that the target-action mechanism only allows for a target, a sender and a message that takes the sender; therefore, if you need to access data, you must get it from the target or the sender.
One option would be to create a class that represents the binding of a parameter value, a method and an object. This class would have an action that invokes the method on the object, passing the value. Use an instance of this class as the target. Here's a simplistic example:
#interface UnaryBinder : NSObject {
id target;
SEL selector;
id parameter;
}
#property id target;
#property SEL selector;
#property (retain) id parameter;
-(id)initWithTarget:(id)anObject selector:(SEL)aSelector param:(id)aParameter;
-(void)action:(id)sender;
#end
#implementation UnaryBinder
...
-(void)action:(id)sender {
[target performSelector:selector withObject:parameter];
}
#end
If you want to support an arbitrary number of parameters, you'd need to use NSInvocation (as Louis mentions) rather than performSelector:withObject. Of course, controls don't retain their targets, so you need some way of keeping the UnaryBinder around. At that point, you might as well skip the special class and just store the data in the control, as you mention in your comment about using KVP. Alternatively, factor out the action into a controller class and use an instance of that as the target. UnaryBinder and its ilk doesn't really offer any advantages when it comes to target-action. For related topics, google "higher order messaging".