Dynamic class name in %init(<class>=<expr>) and %hook <class> to assume type
Opened this issue · 6 comments
TLDR
Specifying the class like %init([<class>=<expr>, …]);
, results in the hooked object (self
) being left without type to the compiler. I understand that not assuming any class is the most sane thing to do, but I was wondering if it would be possible to automatically set the object to a known type or to one that conforms to a protocol in order to avoid casting.
Background
I have a few hooks for iOS 11 and 12 (pre 12.2) that hooks the class MediaControlsPanelViewController
in a few of my tweaks. In iOS 12.2 however, this class was renamed to MRPlatterViewController
. All properties and methods seems to be the same. Thus, I would like to reuse the code within the hook, like:
%ctor {
...
Class c;
if (running iOS 12.2)
c = %c(MRPlatterViewController);
else
c = %c(MediaControlsPanelViewController);
%init(MediaControlsPanelViewController = c);
}
This works fine, but inside the actual hooked code, the compiler does no longer know which type self
has.
I realize that it's possible to do something like this:
@protocol PanelViewController<NSObject>
@property (nonatomic, retain) MediaControlsParentContainerView *parentContainerView;
...
@end
@interface MediaControlsPanelViewController : UIViewController <PanelViewController>
@end
@interface MRPlatterViewController : UIViewController <PanelViewController>
@end
and then in the code cast it to an object that conforms to that protocol:
%hook MediaControlsPanelViewController
- (void)viewDidLoad {
%orig;
UIViewController<PanelViewController> *controller = (UIViewController<PanelViewController> *)self;
controller.parentContainerView...
}
...
instead of using self
. I was wondering if it would be possible to automatically set the object to a known type or to one that conforms to a protocol in order to avoid doing this casting. Ideally this would be done in the %ctor
once instead of once in every hooked method.
Elaborating on this:
For example if f we take the code:
%hook ClassToHook
-(void)hookedMethod {}
%end
%ctor {
%init(ClassToHook = objc_getClass("aClass"));
}
Logos will currently generate the function definition:
static void _logos_method$_ungrouped$ClassToHook$hookedMethod(_LOGOS_SELF_TYPE_NORMAL id _LOGOS_SELF_CONST __unused self, SEL __unused _cmd) {}
and declarations:
@class ClassToHook;
static void (*_logos_orig$_ungrouped$ClassToHook$hookedMethod)(_LOGOS_SELF_TYPE_NORMAL id _LOGOS_SELF_CONST, SEL); static void _logos_method$_ungrouped$ClassToHook$hookedMethod(_LOGOS_SELF_TYPE_NORMAL id _LOGOS_SELF_CONST, SEL);
(notice how it still generates the @class
, but is unused). Logos should instead generate the definition:
static void _logos_method$_ungrouped$ClassToHook$hookedMethod(_LOGOS_SELF_TYPE_NORMAL ClassToHook* _LOGOS_SELF_CONST __unused self, SEL __unused _cmd) {}
and declarations:
@class ClassToHook;
static void (*_logos_orig$_ungrouped$ClassToHook$hookedMethod)(_LOGOS_SELF_TYPE_NORMAL ClassToHook* _LOGOS_SELF_CONST, SEL); static void _logos_method$_ungrouped$ClassToHook$hookedMethod(_LOGOS_SELF_TYPE_NORMAL ClassToHook* _LOGOS_SELF_CONST, SEL);
As would be generated if the class was hooked normally, without being passed into %init
.
@Nosskirneh How exactly is logos supposed to know which class it's supposed to be at compile-time?
@NSExceptional my examples show the output I believe that logos should generate to resolve this issue, and that this is indeed a bug by the unused @class
forward declaration. Normally when hooking with %hook UIView
for example, logos will declare the self
variable as _LOGOS_SELF_TYPE_NORMAL UIView* _LOGOS_SELF_CONST
. However when hooking labels defined in %init
, logos declares self
as _LOGOS_SELF_TYPE_NORMAL id _LOGOS_SELF_CONST
, instead of declaring it as a ClassToHook*
, leaving the @class ClassToHook;
unused.
Ah, my bad. I understand now.
This is really biting me in the ass right now. @uroboro do you know where exactly I might go to resolve this in Logos? I've been digging around for an hour and can't find it
I think I've found it, in bin/lib/Logos/Class.pm
:
sub type {
my $self = shift;
if(@_) { $self->{TYPE} = shift; }
# return $self->{TYPE} if $self->{TYPE};
return $self->{NAME}." *";
}
Commenting out the 2nd-to-last line as above does the trick. @uroboro If this is the only thing type
is used for (and it as AFAICT) then can you just commit this change?