Get the object which called a method - objective-c

If I have a call from within a random class like this:
#implementation SomeClass
- (void) classMethodFoo
{
int a = [SomeSingleton sharedInstance].aValue;
}
#end
Inside SomeSingleton sharedInstance, is there a way to get a reference to the object which called this method (without the called passing self as a parameter of course)?

No, information about the caller isn't passed along automatically.
This is why IBAction methods, for instance, have a sender parameter, and why delegate methods often have a parameter that refers to the delegate's object.

Related

Storing a parameter value to be returned later in delegate callback

I have a singleton class and a protocol defined as below. (Simplified)
#protocol ClassADelegate <NSObject>
- (void) classADelegateDidFinishSomething:(BOOL) aBool;
#end
#interface ClassA : NSObject
#property (nonatomic, weak) id<ClassADelegate> delegate;
+ (ClassA *) shared;
- (void) methodA:(BOOL) aBool;
#end
The methodA method causes a chain of asynchronous callbacks internally and finally in a private method needs to call the delegate method like the following way.
if (self.delegate)
{
[self.delegate classADelegateDidFinishSomething:BOOL_FROM_methodA];
}
Now BOOL_FROM_methodA in the above method must be the same as the aBool in the methodA method. So I have to store the value of the aBool somewhere. Lets say I store it in a private variable _aBool like the following and later using this to call the delegate method.
- (void) classMethodA:(BOOL) aBool
{
_aBool = aBool;
...
}
- (void) aPrivateMethod
{
....
if (self.delegate)
{
[self.delegate classADelegateDidFinishSomething:_aBool];
}
}
This solves the problem if it was guaranteed that no further calls to classMethodA is done before the delegate method is called. But imagine the following situation.
[[ClassA shared] methodA:YES];
[[ClassA shared] methodA:NO];
For the above code, both of the classADelegateDidFinishSomething callbacks will have NO as their parameter value, even though the 1st methodA call has YES as its parameter.
I would like to get an elegant solution to the problem without refactoring most of my code.
You're implementing something that requires context (multiple requests) using structures that are inherently one-to-one (singleton, delegate). This isn't a good match.
Options that come to mind are to use a unique instance of ClassA for each invocation of methodA or to rewrite ClassA methods so that the caller supplies its own context.
For example:
- (void)classMethodA:(BOOL)aBool listener:(id<ClassADelegate>)listener;
That way, you could map each call to the object that made it.
Or, if there's only one delegate making multiple calls, replace the listener object with any kind of context parameter that can be used to tag the calls.
- (void)classMethodA:(BOOL)aBool context:(id)context;
- (void)aPrivateMethod:(id)context;
For either of those options, your singleton can maintain a collection that maps calls to responses.

Is it possible for a class to have a member function?

I've currently got some code as follows:
static void callback(several parameters)
{
...
}
#implementation SomeClass
- (id) init
{
self = [super init];
if (self)
{
id ct = CTTelephonyCenterGetDefault();
CTTelephonyCenterAddObserver((__bridge CFNotificationCenterRef)(ct), NULL, callback, NULL, NULL, CFNotificationSuspensionBehaviorHold);
....
Within the callback function's body I want to update some values, and I'd rather add them as properties of SomeClass rather than be global variables.
So is it possible to make the callback function a member function of SomeClass?
If you're using a C API that takes a callback and you want one of your class's instance methods to be called, you have to use a C function as a trampoline. Along with the callback function, most such C APIs allow you to specify a user value that gets passed back as an argument to callback. You should pass the instance pointer as that user value. Then, your trampoline will just call an instance method on the object.
For example:
static void callback(void* userValue, /* other parameters... */)
{
MyClass* myObject = (__bridge MyClass*)userValue;
[myObject myMethod:/* other parameters passed along */];
}
You'll have to figure out if CTTelephonyCenterAddObserver() can take such a user value argument and which it is.
It doesn't much matter if callback() is declared inside or outside of the #implementation.
So is it possible to make the callback function a member function of
SomeClass
Not really. A method requires an object to act on. What you normally can do, depending on the API you're using, is to store a pointer to your SomeClass instance, and pass it as an additional parameter for the addObserver function.
Presumably one of the NULL arguments in your call to CTTelephonyCenterAddObserver is supposed to be additional context for the callback routine. You can convert a pointer to an object to a (void *) pointer when passing it to the CTTelephonyCenterAddObserver, and then convert it back to a (SomeClass *) inside the callback function.
UPDATE
See my comment below. My answer should not be the accepted answer.
Move callback inside your #implementation, like this:
#implementation
- (void)callback:(SomeType)parameter1 parameter2:(SomeOtherType)parameter2 {
// do stuff
}
...
#end
If you want your method to be public, you need to add it to your interface:
#interface
- (void)callback:(SomeType)parameter1 parameter2:(SomeOtherType)parameter2;
#end
Apple's Objective-C intro may help.

Can subclass override non-public methods

I have two classes: BatchDownloader, SpeechDownlader
BatchDownloader is the base class, and SpeechDownloader inherited it.
In BatchDownloader, whenever one file was downloaded, -(void)downloadComplete:task will be called.
But in SpeechDownloader, I also want to post a notification in downloadComplete:task.
Can I just write the method with the same name in SpeechDownloader's implementation ? or there is a better way ?
Thanks.
p.s. I don't want to make -(void)downloadComplete:task public, because it should only be called by itself.
If you implement a method in a subclass that has the same name as a private method in a superclass, your subclass method will be called on instances of your subclass.
i.e., if you implement a method in your superclass like this, without declaring it anywhere:
#implementation classA
- (void)doSomething {
NSLog("a");
}
Then, in your subclass implementation, implement a method with the same name:
#implementation subclassOfA
- (void)doSomething {
NSLog("b");
}
When you call doSomething on an instance of your subclass, the subclass implementation will be called instead of the superclass implementation, so the code in this example will result in "b" being printed to the console.
However, if you also want to access the superclass implementation of the method, you can use:
- (void)doSomething {
[super doSomething];
NSLog("b");
}
This will also call the superclass implementation. If you get a compile error (due to the method being private and super not appearing to implement it), you can use [super performSelector:#selector(doSomething)] instead to do exactly the same thing.
This happens because of the way the Objective-C runtime looks up method calls. Since these methods have exactly the same method signature (same name, return type and arguments [none]), they are considered equal, and the runtime always checks the class of the object before looking in superclasses, so it will find the subclass method implementation first.
Also, this means you can do this:
classA *test = [subclassOfA new];
[test doSomething];
And, surprise surprise, the console will print "b" (Or "a b" if you called the super implementation too).
If you implement the method with the same method signature it will be called faith your implementation, public or not.

Can someone explain how I might use this function call that includes a delegate?

This is the prototype:
- (void)startDownloadingDataOfType:(NSString *) type fromURL:(NSURL *) url delegate:(id <GetURLAsyncDelegate>) delegate;
There is a delegate set up with methods such as URLDidFinishDownloading and so on. However I stil don't totally understand delegates - I get their point, but I don't really know how to use them.
This function seems to contain a parameter to pass IN a delegate, but surely I want to extract one?
In the class where I want to call this function I essentially want to be able to trigger a method when the URL has finished it's download. What is the syntax for using this kind of function in a class?
Passing the delegate to the prototype will cause the method to be called on the supplied delegate.
If you want the method (URLDidFinishDownloading) to be called when the download is complete in the class you called it from, implement the delegate in that class and specify the URLDidFinishDownloading method.
Something like below - (note: my obj-c isn't the greatest, but hopefully you get the idea)
#interface MyClass : BaseClass<GetURLAsyncDelegate> {
}
#implementation MyClass
-(void)URLDidFinishDownloading {
...
}
-(void)downloadData {
[object startDownloadingDataOfType:#"..." fromUrl:... delegate:self];
}

Passing a class variable pointer to non-class method in Objective C

I have two classes that communicate with each other (processes in each class depend on a couple of objects from the other class). In Class1, I have a CvMat object prevMat1 declared in the interface:
#interface Class1 {
CvMat** prevMat1;
}
#property CvMat** prevMat1;
#end
Now, I have a class method in Class2 that I am passing prevMat1 from Class1 to. I need the method within Class2 to update the value of prevMat1 and that new value be reflected in Class1. I am currently calling this method like this:
[Class2 doSomething:self.prevMat1];
Within Class2 I am handling this object under the name prevMat2. This is the function:
#implementation Class2
+ (void) doSomething: (CvMat**) prevMat2 {
//do some stuff
}
#end
The way this is currently constructed, will self.prevMat1 in Class1 be updated with the new value assigned to prevMat2 in Class2? I fear that it may not be working the way I intend it to since I am not sending a pointer, but the object itself (I think).
Thanks
If prevMat1 is declared as Something** then you're not sending an object when you use it as a parm, you're sending the address of pointer.
(Hopefully you're not retaining prevMat1.)