I am debugging an old project which has got a old library. I am not sure how they have called the block handler from button action method. They have a Class where they have declared a method
+ (void) method: (NSString *) parameter;
In which I guess, they are adding cancel button and action method for the button. They have declared a block as
typedef void (^simpleBlock)(void);
#property (nonatomic, copy) simpleBlock simpleBlock;
And when it is implemented in ViewController class it is called as
[ClassName method:#"parameter"].simpleBlock = ^{
//Do something
};
How they would have linked the block with button action and the method because I couldn't see as it is library, got just header file. Any help on understanding this implementation would be appreciated. Thanks!
For invoking a block on any action we code like this ,
In a TotalLikes_Comments.h ,
#property (nonatomic, copy) void (^LikeButtonTapAction)(TotalLikes_Comments *aCell);
- (IBAction)openLikesClick:(id)sender;
In TotalLikes_Comments.m Actual Implementation of method is
- (IBAction)openLikesClick:(id)sender {
if (self.openLikesTapAction) {
self.openLikesTapAction(self);
}
}
Where whenever the button clicks this block is initializes with the object of class ,
Whenever we want the action no need to write theaction code in the class file just write your code where you have initialized the class eg.in cellforrow atIndexpath
cell.LikeButtonTapAction = ^(TotalLikes_Comments *aCell){
// Do your stuff.
};
Above is the logic for Invoking Block in IBAction.
But In your scenario this is written in Frameworks. In which the the Ibaction Logic is hidden from all. eg.
if(self.openLikesTapAction) {
self.openLikesTapAction(self);
}
Hope you got an idea from this.
Related
I have a helper class which looks something like this:
(We'll call this GUI.H & GUI.M Files)
(DOT . H FILE )
- (CGGroup)addLabelTextField:(UIViewController*)vc deligate:(id<UITextFieldDelegate>)deligate textField:(UITextField*)textField;
(DOT . M FILE )
- (CGGroup)addLabelTextField:(UIViewController*)vc deligate:(id<UITextFieldDelegate>)deligate textField:(UITextField*)textField
{
// Blah, Blah Blah Blah Set Up & Configure Label & Textfield... 10 lines
// DONE Allocating & Configuring OK
// Last 3 Lines -- this is where the Deligate gets SET and the problems
textField.delegate = deligate; // <- this is what is NOT happening
[vc.self.view addSubview:textField]; // this adds TextField to passed in UIViewController
return(cgTmp); // nothing to see here just a typedef of CGRect's
}
I pass a pointer of the ViewController, textField, and textFieldDeligate in and set them programmically (NO xib's what-so-ever)
Alloc, set, ect, is just like you would create / configure a textfield or label in the viewcontroller you were going to use it, except pass that the the helper class sets everything. so adding fields is one call, not all the usual configuring...
Problem:
Everything seems to be working fine, with the except that the TextFieldDeligate functions are NOT getting called (clang -- no warnings, nothing...)
If I move this same code, back into the calling class (uiViewController)
Suddenly, the delegates are getting called, no issues at all...
Another issue: once the testfield is set, you are not able to change things, I.E... SecureText = TRUE to FALSE.... Nothing happens, again when this code is moved back into the calling viewController, Suddenly everything works as advertised....
I suspect something to do with the way the "UITextFieldDeligate" is being passed, but as I mentioned, clang doesn't give ANY warnings... NONE...
The UIViewController is of course set up to support the deligates
and the properties are declared...
(if I move this stuff back into the class (the UIViewController) (without having a separate class for these setting these fields) it works fine...
The method gets called:
SomeUIViewController.M (This is where we call the function defined in GUI.H & M)
[self.gui addTextField:self textField:self.passField deligate:self.passField.delegate];
AND YES There is a Property for the UITextField and the Class has the protocol declared
SomeUIViewController.H
#interface SomeUIViewController : UIViewController <UITextFieldDelegate>{
}
#property (nonatomic, strong) GuiUtils *gui;
#property (nonatomic, strong) UITextField *userField;
#property (nonatomic, strong) UITextField *passField;
#property (nonatomic, strong) UITextField *tmpField;
And as I mentioned b4, the only plroblem I'm experiencing is the deligate methods in the UIViewController (related to this UITextField) are NOT getting called...
(But I think it may be something simple, because I just noticed I'm not passing the deligate as a pointer... So it may have already been solved)
Thanks in advance.....
OK.... The Delegate NOT getting called is FIXED!
I was passing the delegate of the "UITextField.delegate" instead of the delegate of the UIViewController "self"
FROM:
[self.gui addTextField:self textField:self.passField deligate:self.passField.delegate];
TO:
[self.gui addTextField:self textField:self.passField deligate:self];
There is a class alpha which has method -(void)doSomething. There is also a class beta which I've created and can modify as I need. Instance of alpha can only be created by calling [gamma createAlpha].
What I need is to make class beta to inherit alpha and override doSomething while I still have to create instances of alpha via calling [gamma createAlpha].
Is there any way to implement this?
I hope my question makes sense.
Thank you!
Yes. You can use method swizzling. You will need to create category with following code:
#implementation alpha (newDoSomething)
// This is called when the category is being added
+ (void) load {
Method method1 = class_getInstanceMethod(self, #selector(doSomething));
Method method2 = class_getInstanceMethod(self, #selector(swizzleddoSomething));
// this is what switches the two methods
method_exchangeImplementations(method1, method2);
}
- (void)swizzleddoSomething
{
... your code
//You can call super implementation here with following line
//[self swizzleddoSomething];
}
#end
You will still have class alpha. It will be successfully created by [gamma createAlpha], but it will have your implementation of doSomething method.
Background:
I have an object (let's call it BackendClient) that represents connection with server. Its methods are generated to single #protocol and they are all synchronous, so I want to create proxy object that will call them in background. The main problem is return value, which I obviously can't return from async method, so I need to pass a callback. The "easy" way will be copy all BackendClient's methods and add callback argument. But that's not very dynamic way of solving that problem, while ObjectiveC nature is dynamic. That's where performSelector: appears. It solves problem entirely, but it almost kills proxy object transparency.
Problem:
I want to be able to send not declared selector to proxy (subclass of NSProxy) object as if it was already declared.
For example, I have method:
-(AuthResponse)authByRequest:(AuthRequest*)request
in BackendClient protocol. And I want proxy call look like this:
[proxyClient authByRequest:myRequest withCallback:myCallback];
But this wouldn't compile because
No visible #interface for 'BackendClientProxy' declares the selector 'authByRequest:withCallBack:'
OK. Let's calm down compiler a bit:
[(id)proxyClient authByRequest:myRequest withCallback:myCallback];
Awww. Another error:
No known instance method for selector 'authByRequest:withCallBack:'
The only thing that comes to my mind and this point is somehow construct new #protocol with needed methods at runtime, but I have no idea how to do that.
Conclusion: I need to suppress this compilation error. Any idea how to do that?
If I understand it, you have a synchronous, non-threaded, API that you want to be asynchronous for purposes of not blocking, say, the main event loop, etc...
I would add a serial queue to BackgroundClient:
#property(strong) dispatch_queue_t serialQueue;
... somewhere in your -init ...
_serialQueue = dispatch_queue_create(..., serial constant);
Then:
- (void)dispatchOperation:(dispatch_block_t)anOperation
{
dispatch_async(_serialQueue, anOperation);
}
That can be used like:
[myClient dispatchOperation:^{
[myClient doSynchronousA];
id result = [myClient doSynchronousB];
dispatch_async(dispatch_get_main_queue(), ^{
[someone updateUIWithResult:result];
}
}];
That is the easiest way to move the BackgroundClient to an asynchronous model without rewriting it or heavily refactoring it.
If you want to harden the API, then create a class wrapper for BackendClient that holds an instance of the client and the serial queue. Make it such that said class instantiates the client and the rest of your code only retrieves instances from that wrapper. That'll allow you to still have the same dispatchOperation: model, but not require mirroring all the methods.
typedef void(^ AsyncBackendBlock(BackendClient* bc);
#interface AsyncBackend
+(instancetype)asyncBackendWithBackend:(BackendClient*)bc;
#property .... serialQueue;
- (void) dispatchAsync:(AsyncBackendBlock) backBlock;
#end
.m:
#interface AsyncBackend()
#property... BackendClient *client;
#end
#implementation AsyncBackend
- (void) dispatchAsync:(AsyncBackendBlock) backBlock
{
dispatch_async(_serialQueue, ^{
backBlock(_client);
});
}
#end
Caller:
AsyncBackend *b = [AsyncBackend asyncBackendWithBackend:[BackendClient new]];
[b dispatchAsync:^(BackendClient *bc) {
[bc doSomething];
id result = [bc retrieveSomething];
dispatch_async(dispatch_get_main_queue(), ^{
[uiThingy updateWithResult:result];
}
}];
....
To look up a selector at runtime, you can use NSSelectorFromString(), but in this case you should just go ahead and import whatever header you need to get the declaration of -authByRequest:
I am trying to pass a reference of my current NSObject Class through two other object classes so I can access the current initialization of the original NSObject class I called from.
I will try to outline why I am doing this in as simply as possible. I have 3 NSObject Classes and an appDelegate.
AppDelegate
RemoteSites
EngineRequest
EngineReasponse
This is the logical flow of the app as it stands
Appdelegate.m
calls RemoteSites method "GetRemoteSites" this method reutrns a BOOL for confirmation
RemoteSites.m
-(BOOL)GetRemoteSites {
// calls EngineRequests method like so
EngineRequests *engineRequests = [[EngineRequests alloc] init];
[engineRequests GetRemoteSites:self];
//..
}
EngineRequests.m
- (void)GetRemoteSites:(NSObject *)myObjectClass {
// get everything ready to send off request
}
send off request then return recived data + NSObject refrence to EngineReasponse
EngineReasponse.m
- (void)GetRemoteSites:(NSData *)receivedData Object:(NSObject *)requestingClass
{
// pass requestingClass to a NSObject var that will later be used to pass the data back to the original class that started the request
requestingClassObject = requestingClass
}
//..
[requestingClassObject GetRemoteSitesNow:reducedDataPacket]; // GetremoteSitesNow is a method inside RemoteSites class, however using requestingClassObject I cannot see any of the classMethods my class has in it
//..
So thats the overall flow of the process I am trying to complete, the whole point is to try and get -(BOOL)GetRemoteSites to return Yes to the AppDelegate.
In summery my question stands as this. Why can I not access RemoteSites methods from EngineReasponse's, I have passed the class Object refrence correctly I think but for some reason I cannot access the methods.
Any help solving my issue would be greatly appreciated.
EngineRequests.m
- (void)GetRemoteSites:(id)remoteSites {
// create your class object here or globally.
RemoteSites *remotesite = (RemoteSites*)remoteSites
}
EngineReasponse.m
- (void)GetRemoteSites:(NSData *)receivedData Object:(id)requestingClass
{
RemoteSites *requestingClassObject = (RemoteSites*)requestingClass
}
//
[requestingClassObject GetRemoteSitesNow:reducedDataPacket];
//
Sorry for the typo. Hope it will help.
I want to reload + (BOOL)resolveClassMethod:(SEL)sel method to add my custom implementation of unresolved methods in super class, like this:
+ (BOOL)resolveClassMethod:(SEL)sel {
BOOL result = [super resolveClassMethod:sel];
if (result) {
return result;
}
/*my logic here*/
}
But I notice that, when I call +bundleForClass: method with this class it actually invokes resolveClassMethod: with bundleForClass: selector as parameter. And, of course, [super resolveClassMethod:sel]; return NO and it move to my logic. Code:
NSBundle *classBundle = [NSBundle bundleForClass:NSClassFromString(#"MyClass")];
Why code above invoke +resolveClassMethod: on MyClass? I aim to add implementation for my custom class methods to class, but not implementation of standard method like bundleForClass:, so how can I check methods like that to skip it.