Replace method implementation in Swift - ios

I'm trying to replace method implementation with parent implementation:
// Get superclass's valueDisplayText()
// XLFormSelectorCell is a parent of HCFormSelectorCell
// HCFormSelectorCell - swift class
// XLFormSelectorCell - obj-c class
let impParent = class_getMethodImplementation(XLFormSelectorCell.self, Selector("valueDisplayText"))
let method = class_getInstanceMethod(HCFormSelectorCell.self, Selector("valueDisplayText"))
method_setImplementation(method, impParent)
class_replaceMethod(HCFormSelectorCell.self, Selector("valueDisplayText"), impParent, method_getTypeEncoding(method))
But instead in replaces parent implementation with subclass implementation.
Why and how to achieve desired?
P.S: The reason I'm doing this: I need to call parent class's hidden method (obj-c class). Any other approaches to do this?

Related

Is it possible in Swift to create initializer that takes a superclass object as an argument?

For example, I have a simple subclass of UIImage that have some additional properties:
class Image: UIImage {
var poeticDescription: String?
}
What I would like is like this:
init(with: UIImage) { /* something to do here */ }
You cannot initialize an existing object a second time, no matter, if the source object is a superclass object or not. Of course you can call the initializer with a superclass object as argument, but this will create a completely new object.
init(with superclassObject: SuperClass) {
// Do some stuff with superclass object
}
The usual way to do inheriting is calling the superclass initializer in the inherited initializer:
init() {
super.init()
}
But again, in this case you cannot use an already existing superclass object to initialize it again.
Maybe you can explain, what you want to achieve. We can then help you to find the correct way.
I think what you want to achieve is to have a UIImage subclass with custom properties. You have to call a super initializer with the source image's data. For UIImage subclassing is tricky, have a look this answer for an example.

How to override method of

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.

Passing class Object refrence to another class then trying to use it is not working

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.

How to explicitely pass self as a super class to a method and being called back instead of subclass?

I have 3 classes
One base class : MyBaseClass
That implements a method :
- (void) aSuperMethod {
[[UtilClass sharedUtil] doThisAndSendAnswerToMe:self]
}
- (void) answerReader:(bla bla)someParams {}
One subclass of MyBaseClass : MySubClass
That also implements these kind of methods :
- (void) anotherMethod {
[[UtilClass sharedUtil] doThisAndSendAnswerToMe:self]
[self aSuperMethod];
}
- (void) answerReader:(bla bla)someParams {}
And of course a utility class : UtilClass
That implements this kind of method :
- (void) doThisAndSendAnswerToMe:(id)listener {
do some stuff
[listener answerReader:someAnswerParams];
}
In debug mode, of course, the listener received in both calls by the doThisAndSendAnswerToMe method is of MySubClass class.
How may I do to point either on MySubClass or MyBaseClass depending on the call origin ?
You can't. The subclass's method implementation always overrides the superclass implementation.
One solution is to use a different method name in the superclass and the subclass, and pass the name of the callback method to UtilClass. UtilClass then uses -[NSObject performSelector:withObject:] to call that method.
-(void)baseClassAnswerReader:(id)someAnswerParams { ... }
[[UtilClass sharedUtil] doSomethingAndSendAnswerToMe:self
selector:#selector(baseClassAnswerReader:)];
Another solution is to pass a completion block object to UtilClass. UtilClass then calls the block object when it is done.
[[UtilClass sharedUtil] doSomethingWithCompletionBlock:^(id someAnswerParams){ ... }];
You use an instance of the base class if you want to use the base class, and you use an instance of the subclass if you want to use the subclass.
If you don't want the subclass method to override the superclass one, then make it a different method instead of overriding.

Setting delegate in "unrelated" class

I am having trouble using a protocol to get some data from another class. I can't see how to set the delegate in a class that doesn't segue to the MVC that needs the data. I create the protocol in the MVC and implement the method(s) in some arbitrary class that contains the data I need. But I can't see how to refer back to the delegator MVC to set the delegate if there is no reference to the delegator MVC, like when you use segue.destinationViewController.
If MyViewController can create the instance of SomeDataClass, then you set the delegate there. If there is no connection between the controllers, then you might use an NSNotification instead. That is a completely anonymous way to connect instances -- you send out a notification, and any class that registers for that notification can get it.
Something like this?
#implementation MyViewController {
// keep a pointer to the data supplier class as long as this object exists
// so that it will continue to exist and send me delegate callbacks
SomeDataClass *myInstanceOfSomeDataClass; // instance variable to point to my data supplier
}
// ...
- (void)updateMyView {
if (myInstanceOfSomeDataClass == NULL) // I haven't created an instance yet
myInstanceOfSomeDataClass = [[SomeDataClass alloc] init];
SomeType *results;
if (instantResultsAreAvailable)
results = [myInstanceOfSomeDataClass getResults];
if (resultsAreOnlyAvailableFromDelegateCallback)
myInstanceOfSomeDataClass.delegate = self;
}
- (void) delegateCallbackMethod {
//...
}
#end
you want to pass data from one from viewcontroller to another class? just go through this Passing Data between View Controllers

Resources