I have two NSResponder methods (cut, copy) and they have basically the same code except they call their own super. How to create method with parameter _CMD as selector that calls super and I won't end up with recursion?
- (void)copy:(id)sender
{
[self notifyAndPerformSelector:_cmd withObject:sender];
}
- (void)cut:(id)sender
{
[self notifyAndPerformSelector:_cmd withObject:sender];
}
- (void)notifyAndPerformSelector:(SEL)selector withObject:(id)sender
{
[super performSelector:selector withObject:sender];
//code...
}
As you have discovered your code doesn't call the superclass method as you want but the one in the current class, resulting in infinite recursion.
Your first option faced with this is to refactor your code, something along the lines of:
#implementation MyDerivedClass
{
- (void)copy:(id)sender
{
[super copy:sender];
[self commonCodeAfterSelector:_cmd withObject:sender];
}
- (void)cut:(id)sender
{
[super cut:sender];
[self commonCodeAfterSelector:_cmd withObject:sender];
}
- (void)notifyAndPerformSelector:(SEL)selector withObject:(id)sender
{
//code...
}
}
If this approach suits your situation use it. If not...
A second option is to become the compiler...
Standard and super method calls
A standard method call of the form:
[object someMethodWithArg1:x andArg2:y]
invokes a search for the method someMethodWithArg1:andArg2:. This search starts at the runtime class of object. The emphasis on runtime is important, the actual object referenced by object could be of the same class as the declared type of object or and of the subclasses of that type and the search must find the most derived implementation of the method.
A super method call of the form:
[super someMethodWithArg1:x andArg2:y]
also invokes a search for the method someMethodWithArg1:andArg2:. However in this search starts at the compile time class of superclass of the class in which code occurs. For example if MyDerivedClass above is a subclass of MyBaseClass then the search for the method starts at MyBaseClass ignoring the runtime type of self – which could be MyDerivedClass or a subclass of it (say MyDerivedDerivedClass)
Why does your current code recurse?
Your call:
[super performSelector:selector withObject:sender];
starts the search for the method performSelector:withObject: in the superclass, that search won't find the method until it reaches the NSObject class. Once found the method is invoked and starts a standard (not super) search for the method for selector, this search starts at the runtime type of self and so finds the method in MyDerivedClass... recursion.
What you need is something like:
[self performSuperSelector:selector withObject:sender];
but unfortunately that does not exist. But you can make one...
Compiling method calls
The compiler takes a standard method call of the form:
[object someMethodWithArg1:x andArg2:y]
and effectively (we're glossing over a few details, the need ones will get filled in below) compiles this to a call to the runtime function objc_msgSend():
objc_msgSend(object, #selector("someMethodWithArg1:andArg2:"), x, y)
Notice that the selector is passed as a SEL value, this is where the value for _cmd comes from.
A super call of the form:
[super someMethodWithArg1:x andArg2:y]
is effectively compiled to a call to objc_msgSendSuper() of the form:
objc_msgSendSuper(`struct` containing `self` and superclass,
#selector("someMethodWithArg1:andArg2:"), x, y)
You can call these runtime functions directly in your own code. You must import the <objc/objc-runtime.h> to obtain the definitions, cast them to the appropriate type, etc.
Becoming the compiler and bypassing performSelector
Your code uses performSelector as it has a SEL value, but as shown above the runtime calls used for method calling take a SEL directly. If you "compile" the super call yourself you do not need to use performSelector, which in turn avoids the recursion problem.
Before calling objc_msgSendSuper() the function needs to be cast so its return and argument types match the actual return and argument types of the selector you are calling. This is so that the correct code is compiled to handle the arguments and return value, and that code is dependent on the types. The two selectors you are calling, copy: and cut:, have the same type which makes the code shorter. To make the casting easier we first define a shorthand for the type:
typedef void (*CutOrCopyRunner)(struct objc_super *super, SEL op, id sender);
which defines CurOrCopyRunner as a function pointer type. Now your method:
- (void)notifyAndPerformSelector:(SEL)selector withObject:(id)sender
{
// "compile" [super selector:sender];
// first cast objc_msgSendSuper to the correct type by
// casting a function pointer to it (a function name by
// itself, e.g. objc_msgSendSuper, evaluates to a pointer
// to the function)
CutOrCopyRunner msgSender = (CutOrCopyRunner)objc_msgSendSuper;
// now build the first argument struct
struct objc_super superInfo;
superInfo.receiver = self;
superInfo.super_class = MyDerivedClass.class.superclass;
// now execute the super call
msgSender(&superInfo, selector, sender);
// code...
}
HTH
Related
The title basically says it all..
Can I create a Go method that returns another Go method, at runtime? A simple example:
type Person struct {
name string
age uint
}
func (p Person) createGetNameMethod() /*return signature is a method for Person*/ {
return /*return a new anonymous method here for Person*/
}
Are Go methods first class functions?
Yes, they are.
Can I create a Golang method that returns another Golang method [...]?
Yes, of course.
[Can I] return a new anonymous method [?]
No, of course not.
The set of methods is determined at compile time. Methods are normal, first class functions, but they cannot be changed or created during runtime:
You can return a method that exists in the method set, but you cannot add one to the method set.
Reflection allows something like that but not in your case.
Consider this code to extend the Object type:
interface Object
{
doSomething() : void;
}
Object.prototype.doSomething = function ()
{
//do something
}
With this in place, the following both compile:
(this as Object).doSomething();
this.doSomething();
BUT: when I'm typing the first line, Intellisense knows about the doSomething method and shows it in the auto-completion list. When I'm typing the second line, it does not.
I'm puzzled about this, because doesn't every variable derive from Object, and therefore why doesn't Visual Studio show the extra method in the method list?
Update:
Even though the Intellisense doesn't offer the method, it does seem to recognize it when I've typed it manually:
What could explain that?!
...because doesn't every variable derive from Object
No, for two reasons:
1. JavaScript (and TypeScript) has both objects and primitives. this can hold any value (in strict mode), and consequently can be a primitive:
"use strict";
foo();
foo.call(42);
function foo() {
console.log(typeof this);
}
Here's that same code in the TypeScript playground. In both cases (here and there), the above outputs:
undefined
number
...neither of which is derived from Object.
2. Not all objects inherit from Object.prototype:
var obj = Object.create(null);
console.log(typeof obj.toString); // undefined
console.log("toString" in obj); // false
If an object's prototype chain is rooted in an object that doesn't have a prototype at all (like obj above), it won't have the features of Object.prototype.
From your comment below:
I thought even primitives like number inherit from Object. If number doesn't, how does number.ToString() work?
Primitives are primitives, which don't inherit from Object. But you're right that most of them seem to, because number, string, boolean, and symbol have object counterparts (Number, String, Boolean, and Symbol) which do derive from Object. But not all primitives do: undefined and null throw a TypeError if you try to treat them like objects. (Yes, null is a primitive even though typeof null is "object".)
For the four of them that have object counterparts, when you use a primitive like an object like this:
var a = 42;
console.log(a.toString());
...an appropriate type of object is created and initialized from the primitive via the abstract ToObject operation in the spec, and the resulting object's method is called; then unless that method returns that object reference (I don't think any built-in method does, but you can add one that does), the temporary object is immediately eligible for garbage collection. (Naturally, JavaScript engines optimize this process in common cases like toString and valueOf.)
You can tell the object is temporary by doing something like this:
var a = 42;
console.log(a); // 42
console.log(typeof a); // "number"
a.foo = "bar"; // temp object created and released
console.log(a.foo); // undefined, the object wasn't assigned back to `a`
var b = new Number(42);
console.log(b); // (See below)
console.log(typeof b); // "object"
b.foo = "bar"; // since `b` refers to an object, the property...
console.log(b.foo); // ... is retained: "bar"
(Re "see below": In the Stack Snippets console, you see {} there; in Chrome's real console, what you see depends on whether you have the console open: If you don't, opening it later will show you 42; if you do, you'll see ▶ Number {[[PrimitiveValue]]: 42} which you can expand with the ▶.)
Does number implement its own toString method, having nothing to do with Object?
Yes, but that doesn't really matter re your point about primitives and their odd relationship with Object.
So to round up:
this may contain a primitive, and while some primitives can be treated like objects, not all can.
this may contain an object reference for an object that doesn't derive from Object (which is to say, doesn't have Object.prototype in its prototype chain).
JavaScript is a hard language for IntelliSense. :-)
The reference documentation for the class NSUniqueIdentifier claims that unique ID specifiers are evaluated in the following scheme:
If the container implements a method whose selector matches the relevant valueIn<Key>WithUniqueID: pattern established by scripting
key-value coding, the method is invoked. This method can potentially
be very fast, and it may be relatively easy to implement.
As is the case when evaluating any script object specifier, the container of the specified object is given a chance to evaluate the
object specifier. If the container class implements the
indicesOfObjectsByEvaluatingObjectSpecifier: method, the method is
invoked. This method can potentially be very fast, but it is
relatively difficult to implement.
An NSWhoseSpecifier object that specifies the first object whose relevant 'ID ' attribute matches the ID is synthesized and evaluated.
The NSWhoseSpecifier object must search through all of the keyed
elements in the container, looking for a match. The search is
potentially very slow.
However, I am not seeing valueIn<Key>WithUniqueID: getting called. To give you an example, I have a class where I describe the object specifier in the following way:
- (NSScriptObjectSpecifier *)objectSpecifier
{
assert(self.documentID);
assert(self.controller);
NSScriptObjectSpecifier *containerRef = self.controller.objectSpecifier;
assert(containerRef);
assert(containerRef.keyClassDescription);
return [[NSUniqueIDSpecifier alloc] initWithContainerClassDescription:containerRef.keyClassDescription
containerSpecifier:containerRef
key:#"allObjects"
uniqueID:self.documentID];
}
The method I have defined in the container class is - (id)valueInAllObjectsWithUniqueID:(NSString *)uniqueID is the method I have defined:
- (id)valueInAllObjectsWithUniqueID:(NSString *)uniqueID {
return [self objectWithIdentifier:uniqueID];
}
In the class corresponding to the container I've also overridden -respondsToSelector: to debug this further, and observe that the only relevant method the scripting system queries is indicesOfObjectsByEvaluatingObjectSpecifier: right after -objectSpecifier above is called (and confirmed to return a non-nil result with the container class description and container specifier consistent with the container's class receiving method calls right after the object specifier is evaluated).
Any ideas? This is on OSX Mavericks (10.9.4).
Calling ObjectSpace.each_object(Class) does not seem to return any eigenclasses. For example, when investigating Ruby metaclasses: why three when defined singleton methods?, I found that while ObjectSpace.count_objects[:T_CLASS] was getting incremented by 3 in the case of defining a new class with a class method, ObjectSpace.each_object(Class).count was only being incremented by one.
Is there any way to enumerate the eigenclasses active in the system?
Looking at MRI C code, the function ObjectSpace.each_object tests if the object is an internal object and if it is true the object is removed from the iterator.
The test is made by the following function, which consider the classes internally flagged as singleton as an internal object:
static int
internal_object_p(VALUE obj)
{
RVALUE *p = (RVALUE *)obj;
if (p->as.basic.flags) {
switch (BUILTIN_TYPE(p)) {
case T_NONE:
case T_ICLASS:
case T_NODE:
case T_ZOMBIE:
break;
case T_CLASS:
if (FL_TEST(p, FL_SINGLETON)) /* Here */
break;
default:
if (!p->as.basic.klass) break;
return 0;
}
}
return 1;
}
The Ruby EigenClasses are flagged as Singleton, so it will be not returned.
It is important to mention that, the singleton flag used internally by the MRI is different from the Singleton module from standard library.
If you create a class and include the Singleton module on it, it will be returned by the ObjectSpace.each_object method.
I want to have a static variable in Cocoa.
After looking at How do I declare class-level properties in Objective-C?, I am unclear whether there is anything wrong with what I have always done so far, i.e.
// Foo.m
static NSString* id;
#interface Foo ()
instead of
// Foo.h
#interface Foo {
}
+(NSString*) id;
// Foo.m
+(NSString*) id
{
static NSString* fooId = nil;
if (fooId == nil)
{
// create id
}
return fooId;
}
Obviously, the second approach offers an opportunity for initializing the id. But if I initialize the id myself somewhere else in the code, within, say a getter:
-(NSString*) getId
{
if (id==nil) {
id = ... // init goes here
}
return id;
}
Then is there anything wrong with the simple static declaration approach as opposed to the more complex class function approach? What am I missing?
First, what you are asking for is a global variable, a static is similar but a little bit different...
Putting a static declaration outside of any #interface in a header (.h) file will create a different variable in each implementation (.m) file you include the header in - not what you want in this case.
So static on a declaration creates a variable whose lifetime is that of the whole application execution but which is only visible within the compilation unit (e.g. the implementation file) in which it appears - either directly or via inclusion.
To create a global variable visible everywhere you need to use extern in the header:
extern NSString *id;
and in your implementation repeat the declaration without the extern:
NSString *id;
As to what is wrong with global variable vs. class methods, that is a question on program design and maintainability. Here are just a few points to consider:
With a method the value cannot be changed unless you provide a setter method as well as getter method. Variables are always read-write.
Namespace pollution: a class method is only valid when paired with its class name ([YourClass id]); the variable name is valid everywhere it's included simply as id; that both pollutes the name space and loses the connection between id and YourClass - which leads us to...
Encapsulation: globals variables break strong encapsulation, and encapsulation aids program design and maintenance - this is a big topic.
That said, there can be a time and a place for globals, sometimes...
After question updated
A static variable declared in the implementation is effectively a "class variable" - a variable shared by all instances of the class.
The pros'n'cons of a class variable vs. setter & getter class methods are exactly the same as the pros'n'cons of an instance variable vs. properties & setter/getter instance methods.
Class setters/getters allow for validation and other logic to be executed on each read/write; and localization of memory management - in short the abstraction and encapsulation benefits of any method.
Therefore whether you use a variable or a setter/getter depends on your application. It is the same question as whether you use an instance variable or setter/getter/property.