问题
Today I was working on a project in which I wanted to "alias" an alternative method for all instances of NSArray
, and didn't think it would be too difficult with some good old-fashioned method swizzling.
I broke out JRSwizzle and…
[NSArray jr_swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(objectAtIndex_accordingToMe:) error:nil];
To be clear, I paired this with the appropriate category on NSArray
, an instance method called objectAtIndex_accordingToMe:
.
However, I was just getting that same old object, at that same old index. Sigh. Ultimately, I figured out that despite not throwing any errors - I'm not going to achieve these results due to the fact that NSArray is a class cluster
I guess my question is more of an unwillingness to accept that "this" is really the end of the road trying to override NSArray
methods. I mean, come on this is NSArray
.. people must wanna muck around with it, no? One would think that Apple's foundation classes would be a prime target for swizzlers, everywhere!
So, is there a way to alter, alias, monkey-patch, override, or otherwise have your way with… an NSArray, etc. (without subclassing)?
回答1:
Presumably you have a particular array for which you'd like this behavior. You can get that instance's class object, no matter what it is, and swizzle that quite easily:
[[myArray class] jr_swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(objectAtIndex_accordingToMe:) error:nil];
There's also only a few concrete subclasses of NSArray
:
NSArray * trees = [NSArray array];
NSArray * birds = [NSArray arrayWithObjects:@"Albatross", @"Budgerigar", @"Cardinal", nil];
NSMutableArray * dogs = [NSMutableArray arrayWithObjects:@"Airedale", @"Beagle", @"Collie", nil];
NSLog(@"%@ %@ %@", [trees class], [birds class], [dogs class]);
We get __NSArrayI
for the first two and __NSArrayM
for the third, so potentially (this is very fragile) you could use a runtime function to grab the class object by name:
[objc_getClass("__NSArrayI") jr_swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(objectAtIndex_accordingToMe:) error:nil];
回答2:
It's not just that it's a class cluster. NSArray
is toll-free bridged to CFArray
, and you can't swizzle Core Foundation. So this is very unlikely to work in general.
But what are you trying to solve? If you want to add a new method, use a category. They work on class clusters just fine. Modifying the behavior of some built-in on NSArray seems a recipe for disaster (entertaining as it might be as an exercise).
Before going too far, you probably want to at least take a look at CFArray.c and understand how some of the underlying stuff is implemented.
EDIT: While I would never do this in production code, you may get some of what you want by hijacking individual array instances with ISA-swizzling. See ISASwizzle for some example code. The code explanation is in Chapter 20 of iOS:PTL. Search out for "isa swizzle" and you should find more on the net. It's how KVO is implemented. But with NSArray... wow, that's gotta be fragile.
来源:https://stackoverflow.com/questions/11751473/is-there-any-way-to-monkey-patch-or-swizzle-an-nsarray-or-other-class-cluster