NermaN
NermaN

Reputation: 185

How to use method swizzle or something on subclasses

I has many UITableViewController subclasses in my app.

Now i just needed to modify them all to add +1 row in all cases, and one simple equal row in all.

I do not want to modify all of them by hand, better way seem's to replace UITableViewDataSource method to modify values in way like:

+(void)load {
[[self class] jr_swizzleMethod:@selector(tableView:numberOfRowsInSection:) withMethod:@selector(swizzledTableView:numberOfRowsInSection:) error:nil];
}

- (NSInteger)swizzledTableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self swizzledTableView:tableView numberOfRowsInSection:section] + 1;
}

But it replaces superclass function, that does not called in subclasses, so this is not working. Is there method to do that what i want, without modifying all subclasses?

Upvotes: 3

Views: 1683

Answers (4)

natanavra
natanavra

Reputation: 2150

I'm probably late for the train... But for future reference, a solution for the problem would be to swizzle setDataSource of UITableView and replace it with an NSProxy instance. Usually nobody overrides the setDelegate / setDataSource methods, and that would allow you to swizzle those and intercept all calls to these delegates and exchange the implementation.

Check this out for more info: https://developer.apple.com/documentation/foundation/nsproxy

Upvotes: 1

Rob Napier
Rob Napier

Reputation: 299285

You'd need to swizzle every subclass specifically. You can find them by introspecting the class hierarchy at runtime with objc_getClassList, but I can't begin to describe how dangerous and fragile this approach is. You're trying to apply this to every tableview in the system, which you hope is just the tableviews you mean it to be (i.e. your tableviews). But what about tableviews that might be used by the system or from third-party libraries? You're modifying them, too. And when you try to understand the crash this causes, the stack trace will be unintelligible because of the swizzle.

In order for this to work, tableView:cellForRowAtIndexPath: also needs to correctly handle this extra row, so it's hard to see how every table view controller in the system is going to be implemented correctly without knowing about this +1.

Either subclass your table view controller (and have them call super), or use a separate object that all of them call to add the extra row if it's needed. This other object (or superclass) is also where you should handle the cell for this extra row.

Upvotes: 2

Aliaksandr
Aliaksandr

Reputation: 104

I have little experience in swizzling. But I have two possible solutions to your problem.

First: Create a subclass: YouBaseTableView: UITableView, and add a row in YouBaseTableView. And inherit all your table view classes from YouBaseTableView.

Second: Create an extension for UITableView, and write your row in this extension.

Upvotes: 1

gnasher729
gnasher729

Reputation: 52538

You are going into two different areas that need full understanding to be used correctly and are highly dangerous: Performing code in the +load method, and using method swizzling. I would never dare doing anything in +load. +initialize is ok if you know what you are doing, but +load is something you mustn't even think of touching if you ask questions here.

Now ask yourself first: What is "self" in a class method, and what is "[self class]"? Do you think this has even a chance of working?

I'd also recommend that you google for "swizzle" and pick up some other code for method swizzling. It looks quite dubious to me. And writing it as a category instead of a plain C function feels just horrible.

Upvotes: 0

Related Questions