I have an instance method that isn't declared in the header file (private) that i still want to use from any other instance method in that class for example
Header with public methods
#interface Tap : NSObject
- (void)enable;
- (void)disable;
#end
Class Impl
#implementation Tap
- (CGEventRef)callback:(CGEventTapProxy)proxy :(CGEventType)type :(CGEventRef)event :(void *)context {
...
}
- (void)enable {
CGEventTapCreate(tap, place, options, mask, /* How to pass the callback here? */, context);
}
...
#end
it seems like i can't just use something like self.callback, so how can i pass this method to the EventTap?
there is no problem mixing C in your implementation
CGEventRef eventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
// when userinfo is used as reference to the object
Tap *tap = (__bridge Tap *)refcon;
[tap exampleMethod];
// your logic here ..
return event;
}
- (void)enable {
void *userinfo = (__bridge void *)(self);
CGEventTapCreate(tap, place, options, mask, (CGEventTapCallBack)eventCallback, userinfo);
}
Related
By Objective-C object I mean something like MyViewController, and a class object MyViewController.superclass.
For example, in this function how would you cast self using targetClass?
// This code doesn't compile
- (void) useOtherClassImplementation :(Class) targetClass :(SEL) targetSelector {
if ([self isKindOfClass: targetClass]) {
((void (*)(id, SEL))[((targetClass *) self) methodForSelector:selector])(self, selector);
}
}
Is there a way to do something like ((targetClass *) self), which doesn't compile?
Case study
Overview:
When ViewController appears, ViewController.viewDidAppear is called and the swizzled implementation runs. After ViewController.viewDidAppear swizzled implementation runs, the original implementation is called. Good.
When the ViewController.viewDidAppear original implementation runs, UIViewController.viewDidAppear is called by super.viewDidAppear(). The swizzled implementation for UIViewController.viewDidAppear is called and run, and in that swizzled implementation self is used to call the original implementation BUT since self is ViewController and not UIViewController at runtime, ViewController.viewDidAppear swizzled implementation is called again and thus a recursive loop begins.
In other words, the recursive loop starts when a child's method, which has been swizzled, calls its super's method, which has also been swizzled. In the swizzled method self is used to call the original implementation, and since self at runtime is the most child class (in this example ViewController) the super's swizzled method calls the child's original method again, and so the cycle repeats.
Goal:
Find a way to call a swizzled class's original implementation.
When self at runtime could be some child, and both the parent and child have their methods swizzled where the child method calls the parent method, there has to be a way to explicitly choose which class's implementation to run by using the runtime function class_getInstanceMethod
Tried and failed:
Casting self as another class because I cannot find out how to use the Class object to cast. To use this swizzling code in a more generic case, a Class object storing the original class has to be used instead of explicitly writing the class type.
ViewController.swift
// Child class ViewController inherits from parent class UIViewController
class ViewController: UIViewController {
override func viewDidLoad() {
_ = ViewController.swizzleViewDidAppearParentAndChild
}
override func viewDidAppear(_ animated: Bool) {
// NOTICE the call to parent's function
super.viewDidAppear(animated)
// never reaches here
print("In viewcontroller viewdidappear")
}
// swizzles in the block for both UIViewController and ViewController
// recursively prints
// TestApp.ViewController is about to perform viewDidAppear:
//
static var swizzleViewDidAppearParentAndChild: Void = {
SwizzledObject.createTrampoline(for: UIViewController.self, selector: #selector(UIViewController.viewDidAppear(_:)), with: printBeforePerforming)
SwizzledObject.createTrampoline(for: ViewController.self, selector: #selector(ViewController.viewDidAppear(_:)), with: printBeforePerforming)
}()
// a block to be used before a method call
static var printBeforePerforming: SelectorTrampolineBlock {
return { target, selector in
print("\(NSStringFromClass(type(of: target as AnyObject))) is about to perform \(NSStringFromSelector(selector!))")
}
}
}
NSObject+Swizzling.h
#import <Foundation/Foundation.h>
#interface SwizzledObject : NSObject
typedef void (^ SelectorTrampolineBlock)(id target, SEL targetSelector);
+ (SEL) createTrampolineForClass:(Class)targetClass selector:(SEL)targetSelector withBlock:(SelectorTrampolineBlock) block;
#end
NSObject+Swizzling.m
#import "NSObject+Swizzling.h"
#import <objc/runtime.h>
#implementation SwizzledObject
// creates a method at runtime that calls the trampolineBlock, and then performs original method
+ (SEL) createTrampolineForClass:(Class)targetClass selector:(SEL)targetSelector withBlock:(SelectorTrampolineBlock) block {
SEL trampolineSelector = NSSelectorFromString([NSString stringWithFormat:#"performBefore__%#", NSStringFromSelector(targetSelector)]);
Method originalMethod = class_getInstanceMethod(targetClass, targetSelector);
if (originalMethod == nil) {
return nil;
}
IMP dynamicImp = imp_implementationWithBlock(^(id self, bool param) {
block(self, targetSelector);
if (!self || ![self respondsToSelector:trampolineSelector]) {return;}
((void (*)(id, SEL, bool))[self methodForSelector:trampolineSelector])(self, trampolineSelector, param);
});
class_addMethod(targetClass, trampolineSelector, dynamicImp, method_getTypeEncoding(originalMethod));
Method newMethod = class_getInstanceMethod(targetClass, targetSelector);
if (newMethod == nil) {
return nil;
}
[SwizzledObject injectSelector:targetClass :trampolineSelector :targetClass :targetSelector];
return trampolineSelector;
}
// Switches/swizzles method
+ (BOOL) injectSelector:(Class) swizzledClass :(SEL) swizzledSelector :(Class) originalClass :(SEL) orignalSelector {
NSLog(#"Injecting selector %# for class %# with %#", NSStringFromSelector(orignalSelector), NSStringFromClass(originalClass), NSStringFromSelector(swizzledSelector));
Method newMeth = class_getInstanceMethod(swizzledClass, swizzledSelector);
IMP imp = method_getImplementation(newMeth);
const char* methodTypeEncoding = method_getTypeEncoding(newMeth);
BOOL existing = class_getInstanceMethod(originalClass, orignalSelector) != NULL;
if (existing) {
class_addMethod(originalClass, swizzledSelector, imp, methodTypeEncoding);
newMeth = class_getInstanceMethod(originalClass, swizzledSelector);
Method orgMeth = class_getInstanceMethod(originalClass, orignalSelector);
method_exchangeImplementations(orgMeth, newMeth);
}
else {
class_addMethod(originalClass, orignalSelector, imp, methodTypeEncoding);
}
return existing;
}
#end
Output
2018-04-04 17:50:43.201458-0700 TestApp[26612:6527489] Injecting selector viewDidAppear: for class UIViewController with performBefore__viewDidAppear:
2018-04-04 17:50:43.202641-0700 TestApp[26612:6527489] Injecting selector viewDidAppear: for class TestApp.ViewController with performBefore__viewDidAppear:
TestApp.ViewController is about to perform viewDidAppear:
TestApp.ViewController is about to perform viewDidAppear:
TestApp.ViewController is about to perform viewDidAppear:
(infinitely prints previous line)
Here is an example of how you might do it:
- (void)useSuperclassImplementation:(Class)targetClass targetSelector:(SEL)targetSelector {
if ([self isKindOfClass: targetClass] && [targetClass respondsToSelector:targetSelector]) {
((void (*)(id, SEL))[targetClass methodForSelector:targetSelector])(self, targetSelector);
}
}
You could use [targetClass performSelector:targetSelector]; and ignore the warning
There's a detailed explanation of the solution on this answer: https://stackoverflow.com/a/20058585/1755720
edit:
struct objc_super superInfo = {
.receiver = [self class],
.super_class = targetClass
};
id (*objc_superAllocTyped)(struct objc_super *, SEL) = (void *)&objc_msgSendSuper;
(*objc_superAllocTyped)(&superInfo, targetSelector);
^ is also another option to invoke super directly, but it's not too safe as you would really need to be certain the target class is the superclass - and I need to ask, why are you doing this? There might be a simpler solution to the problem.
Phrasing this as casting is just confusing, to the reader and probably yourself. Type casting is a purely static, compile-time thing. targetClass, being a variable, is, of course, a dynamic, run-time thing. At run-time, the static type of the message receiver expression has no bearing on the behavior of the code. That information is more or less gone at that point. Both [self someMethod...] and [(AnyType*)self someMethod...] will have been compiled to the exact same code.
Are you just looking for:
[targetClass instanceMethodForSelector:selector]
where you currently have:
[((targetClass *) self) methodForSelector:selector]
?
I've encountered a bit of a poser involving NSTreeController and KVO. NSTreeController's selectionIndexPaths property is documented as being KVO-observable—and when I observe it directly, it works perfectly. However, if I list NSTreeController's selectionIndexPath as a dependency of some other property, and then try to observe that, the notifications are not fired when one would expect.
Here's the shortest sample code I could come up with to demonstrate what I mean:
import Cocoa
class ViewController: NSViewController {
// Our tree controller
#IBOutlet dynamic var treeController: NSTreeController!
// Some random property on my object; you'll see why it's here later
#objc dynamic var foo: String = "Foo"
// A quick-and-dirty class to give us something to populate our tree with
class Thingy: NSObject {
#objc let name: String
init(_ name: String) { self.name = name }
#objc var children: [Thingy] { return [] }
}
// The property that the tree controller's `Content Array` is bound to
#objc dynamic var thingies: [Thingy] = [Thingy("Foo"), Thingy("Bar")]
// Dependencies for selectionIndexPaths
#objc private static let keyPathsForValuesAffectingSelectionIndexPaths: Set<String> = [
#keyPath(treeController.selectionIndexPaths),
#keyPath(foo)
]
// This property should be dependent on the tree controller's selectionIndexPaths
// (and also on foo)
#objc dynamic var selectionIndexPaths: [IndexPath] {
return self.treeController.selectionIndexPaths
}
// Some properties to store our KVO observations
var observer1: NSKeyValueObservation? = nil
var observer2: NSKeyValueObservation? = nil
// And set up the observations
override func viewDidLoad() {
super.viewDidLoad()
self.observer1 = self.observe(\.selectionIndexPaths) { _, _ in
print("This is only logged when foo changes")
}
self.observer2 = self.observe(\.treeController.selectionIndexPaths) { _, _ in
print("This, however, is logged when the tree controller's selection changes")
}
}
// A button is wired to this; its purpose is to set off the
// KVO notifications for foo
#IBAction func changeFoo(_: Any?) {
self.foo = "Bar"
}
}
In addition, the following setup is done in the storyboard:
Add a tree controller, and connect the view controller's treeController outlet to it.
Bind the tree controller's "Content Array" binding to thingies on the view controller.
Set the tree controller's "Children Key Path" to children.
Create an outline view, and bind its "Content" and "Selection Index Paths" bindings to arrangedObjects and selectionIndexPaths respectively on the tree controller.
Create a button, and point it at the view controller's changeFoo: method.
If you'd like to try it yourself, I've uploaded a sample project here.
The behavior is as follows:
The notification for observer2 is always fired whenever the outline view's (and thus the tree controller's) selection changes, as one would expect.
However, the notification for observer1 is not fired when the outline view's selection changes.
However, observer1's notification is fired when the button is clicked, and foo is changed. This suggests that the property's dependencies are being considered, but just not for this one particular key path.
Using the old-school method with an observeValue(forKeyPath:bla:bla:bla:) override instead of the swank Swift 4 closure-based system seems to behave the same way.
EDIT: Well, it's not Swift's fault! Same thing happens when I write this program in Objective-C:
#interface Thingy: NSObject
#property (nonatomic, copy) NSString *name;
- (instancetype)initWithName:(NSString *)name;
#end
#implementation Thingy
- (instancetype)initWithName:(NSString *)name {
self = [super init];
if (self == nil) {
return nil;
}
self->_name = name;
return self;
}
- (NSArray *)children { return #[]; }
#end
void *ctxt1 = &ctxt1;
void *ctxt2 = &ctxt2;
#interface ViewController()
#property (nonatomic, strong) IBOutlet NSTreeController *treeController;
#property (nonatomic, copy) NSString *foo;
#property (nonatomic, copy) NSArray *thingies;
#end
#implementation ViewController
+ (NSSet *)keyPathsForValuesAffectingSelectionIndexPaths {
return [NSSet setWithObjects:#"treeController.selectionIndexPaths", #"foo", nil];
}
- (NSArray *)selectionIndexPaths {
return self.treeController.selectionIndexPaths;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.thingies = #[[[Thingy alloc] initWithName:#"Foo"], [[Thingy alloc] initWithName:#"Bar"]];
[self addObserver:self forKeyPath:#"selectionIndexPaths" options:0 context:ctxt1];
[self addObserver:self forKeyPath:#"treeController.selectionIndexPaths" options:0 context:ctxt2];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if (context == ctxt1) {
NSLog(#"This only gets logged when I click the button");
} else if (context == ctxt2) {
NSLog(#"This gets logged whenever the selection changes");
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (IBAction)changeFoo:(__unused id)sender {
self.foo = #"Bar";
}
#end
I've been staring at this for a while, and I cannot figure out why directly observing treeController.selectionIndexPaths works, but observing a property that depends on treeController.selectionIndexPaths does not. And since I've generally felt like I had a pretty good handle on KVO and its workings, it is really bugging me that I can't explain this.
Does anyone know the reason for this discrepancy?
Thanks!
I'm trying to get a better grip on the Factory Pattern as illustrated here:
http://www.oodesign.com/factory-pattern.html
The examples are in Java, and I'm not a very strong Java programmer. I mostly don't understand the Constructor product ... = cClass... String.class line. I think I've got the "concept," but are these two code blocks analogous?
Furthermore, is there an example in Cocoa Foundation that uses this pattern? The only one I can think of is in UIKit registering cell classes against a UITableView.
Java:
class ProductFactory
{
private HashMap m_RegisteredProducts = new HashMap();
public void registerProduct (String productID, Class productClass)
{
m_RegisteredProducts.put(productID, productClass);
}
public Product createProduct(String productID)
{
Class productClass = (Class)m_RegisteredProducts.get(productID);
Constructor productConstructor = cClass.getDeclaredConstructor(new Class[] { String.class });
return (Product)productConstructor.newInstance(new Object[] { });
}
}
Objective-C:
#interface ProductFactory : NSObject
- (void)registerProduct:(Class)productClass withIdentifier:(NSString *)identifier;
- (id)newProductForIdentifier:(NSString *)identifier;
#end
#interface ProductFactory();
#property (strong, nonatomic) NSMutableDictionary *registeredProducts;
#end
#implementation ProductFactory
- (id)init
{
self = [super init];
if (self) {
_registeredProducts = [NSMutableDictionary dictionary];
}
return self;
}
- (void)registerProduct:(Class)productClass withIdentifier:(NSString *)identifier
{
self.registeredProducts[identifier] = NSStringFromClass(productClass);
}
- (id)newProductForIdentifier:(NSString *)identifier
{
NSString *classString = self.registeredProducts[identifier];
Class productClass = NSClassFromString(classString);
return [[productClass alloc] init];
}
#end
Yes, that is generally analogous. I haven't done java for a little while so I can't explicitly explain the Constructor line but it's kind of like the definition of a designated initialiser and how to find it.
You could do a little work with #protocols to allow a range of init methods to be available for the instantiation and interrogate the class to see which protocol it conforms to (using conformsToProtocol:).
I want to use a block as a callback function. I store my block as a property in my class that does the calling back:
#interface MyParameter
{
float myValue;
void (^callback)(float);
}
#property(copy) void (^callback)(float);
#end
#implementation MyParameter
#synthesize callback;
- (void) valueChanged
{
callback(myValue);
}
#end
Then I set the callback:
MyParameter * param = [[MyParameter alloc] init];
[param setCallback:^(float value) { [self doSomethingWithValue:value]; }];
So far so simple. In reality, MyParameteris a generic abstraction which holds details on a runtime-determined number of different types of parameter. I can have continuous (float) values, discrete values (int) and booleans. So next, I tried this:
#interface MyParameter
{
float floatVal;
int intVal;
void (^contCallback)(float);
void (^discCallback)(int); // And a boolean one too but let's keep this short
ParamType type; // enum of types ie enum ParamType { Continuous, Discrete, Boolean };
}
#property(copy) void (^contCallback)(float);
#property(copy) void (^discCallback)int);
#end
#implementation MyParameter
#synthesize contCallback;
#synthesize discCallback;
- (void) valueChanged
{
switch (type) {
case Continuous:
contCallback(floatVal);
break;
case Discrete:
discCallback(intVal);
break;
// Leave default out for brevity
}
}
#end
Which is getting uglier. I want to keep just one ^callback as an ivar/property. I then want to set it like this:
MyParameter *contParam = [[MyParameter alloc] init];
[contParam setCallback:(^float value) { [self doSomethingContinuous:value]; }];
MyParameter *discreteParam = [[MyParameter alloc] init];
[discreteParam setCallback:(^int value) { [self doSomethingDiscrete:value]; }];
Inside MyParameter my valueChanged method would retain the switch/case from above, to decide what to pass in to the callback.
Is this possible?
Pass your parameter as an NSNumber. You can recover its original type using -objCType which will return a string indicating a type encoding. This way you don't have to polymorph your function call.
Alternately, if NSNumber turns out to be too inflexible, just create your own Argument data class that encodes whatever information you need. If necessary, you can also create a Result data class for the return type.
I'm fairly new to Objective-C and wondering if it's possible to type objects as their supertype without receiving compiler warnings when assigning them, or if there is a recognised way of achieving the same thing?
I realise that this is what type id is for but I have a base class with synthesized properties and if I try to use id I get a build error "request for member 'x' in something not a structure or union", presumably because dynamic typing is fine for sending messages to an object but not for accessing synthesized properties.
For example in Java I might have:
public abstract class A {
public function doSomething() {
//some func
}
}
public class B extends A {
public function doSomething() {
//override some func
}
}
public class C extends A {
public function doSomething() {
//override some func
}
}
//and in my main class:
A objB = new B();
A objC = new C();
//the purpose of all of this is so I can then do:
A objHolder;
objHolder = objB;
objHolder.doSomething();
objHolder = objC;
objHolder.doSomething();
I currently have the above working in Objective-C but with a compiler warning: "assignment from distinct Objective-C type"
OK, here is the Objective-C interfaces, I can add the implementations if you want. It's a composite pattern:
//AbstractLeafNode
#import <Foundation/Foundation.h>
#interface AbstractLeafNode : NSObject {
NSString* title;
AbstractLeafNode* parent;
}
#property (nonatomic, retain) NSString* title;
#property (nonatomic, retain) AbstractLeafNode* parent;
#end
//Page
#import "AbstractLeafNode.h"
#interface Page : AbstractLeafNode {
//there will be stuff here later!
}
#end
//Menu
#import "AbstractLeafNode.h"
#interface Menu : AbstractLeafNode {
NSMutableArray* aChildren;
}
- (void)addChild:(AbstractLeafNode *)node;
- (void)removeChild:(AbstractLeafNode *)node;
- (AbstractLeafNode *)getChildAtIndex:(NSUInteger)index;
- (AbstractLeafNode *)getLastChild;
- (NSMutableArray *)getTitles;
#end
// I'd then like to do something like (It works with a warning):
AbstractLeafNode* node;
Menu* menu = [[Menu alloc] init];
Page* page = [[Page alloc] init];
node = menu;
[node someMethod];
node = page;
[node someMethod];
// Because of the synthesized properties I can't do this:
id node;
// I can do this, but I suspect that if I wanted synthesized properties on the page or menu it would fail:
node = (AbstractLeafNode*)menu;
node = (AbstractLeadNode*)page;
Sorry, as I was editing the question I realised that I was trying to do it the wrong way round and assign an AbstractLeafNode to a Menu, so the compiler warning completely makes sense. No errors when assigning a Menu to an AbstractLeafNode.
I've been staring at this for too long!