If you have an NSMutableArray, how do you shuffle the elements randomly?
(I have my own answer for this, which is posted below, but I'm new to Cocoa and I'm interested to know if there is a better way.)
Update: As noted by #Mukesh, as of iOS 10+ and macOS 10.12+, there is an -[NSMutableArray shuffledArray] method that can be used to shuffle. See https://developer.apple.com/documentation/foundation/nsarray/1640855-shuffledarray?language=objc for details. (But note that this creates a new array, rather than shuffling the elements in place.)
I solved this by adding a category to NSMutableArray.
Edit: Removed unnecessary method thanks to answer by Ladd.
Edit: Changed (arc4random() % nElements) to arc4random_uniform(nElements) thanks to answer by Gregory Goltsov and comments by miho and blahdiblah
Edit: Loop improvement, thanks to comment by Ron
Edit: Added check that array is not empty, thanks to comment by Mahesh Agrawal
// NSMutableArray_Shuffling.h
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#else
#include <Cocoa/Cocoa.h>
#endif
// This category enhances NSMutableArray by providing
// methods to randomly shuffle the elements.
#interface NSMutableArray (Shuffling)
- (void)shuffle;
#end
// NSMutableArray_Shuffling.m
#import "NSMutableArray_Shuffling.h"
#implementation NSMutableArray (Shuffling)
- (void)shuffle
{
NSUInteger count = [self count];
if (count <= 1) return;
for (NSUInteger i = 0; i < count - 1; ++i) {
NSInteger remainingCount = count - i;
NSInteger exchangeIndex = i + arc4random_uniform((u_int32_t )remainingCount);
[self exchangeObjectAtIndex:i withObjectAtIndex:exchangeIndex];
}
}
#end
You don't need the swapObjectAtIndex method. exchangeObjectAtIndex:withObjectAtIndex: already exists.
Since I can't yet comment, I thought I'd contribute a full response. I modified Kristopher Johnson's implementation for my project in a number of ways (really trying to make it as concise as possible), one of them being arc4random_uniform() because it avoids modulo bias.
// NSMutableArray+Shuffling.h
#import <Foundation/Foundation.h>
/** This category enhances NSMutableArray by providing methods to randomly
* shuffle the elements using the Fisher-Yates algorithm.
*/
#interface NSMutableArray (Shuffling)
- (void)shuffle;
#end
// NSMutableArray+Shuffling.m
#import "NSMutableArray+Shuffling.h"
#implementation NSMutableArray (Shuffling)
- (void)shuffle
{
NSUInteger count = [self count];
for (uint i = 0; i < count - 1; ++i)
{
// Select a random element between i and end of array to swap with.
int nElements = count - i;
int n = arc4random_uniform(nElements) + i;
[self exchangeObjectAtIndex:i withObjectAtIndex:n];
}
}
#end
If you import GameplayKit, there is a shuffled API:
https://developer.apple.com/reference/foundation/nsarray/1640855-shuffled
let shuffledArray = array.shuffled()
A slightly improved and concise solution (compared to the top answers).
The algorithm is the same and is described in literature as "Fisher-Yates shuffle".
In Objective-C:
#implementation NSMutableArray (Shuffle)
// Fisher-Yates shuffle
- (void)shuffle
{
for (NSUInteger i = self.count; i > 1; i--)
[self exchangeObjectAtIndex:i - 1 withObjectAtIndex:arc4random_uniform((u_int32_t)i)];
}
#end
In Swift 3.2 and 4.x:
extension Array {
/// Fisher-Yates shuffle
mutating func shuffle() {
for i in stride(from: count - 1, to: 0, by: -1) {
swapAt(i, Int(arc4random_uniform(UInt32(i + 1))))
}
}
}
In Swift 3.0 and 3.1:
extension Array {
/// Fisher-Yates shuffle
mutating func shuffle() {
for i in stride(from: count - 1, to: 0, by: -1) {
let j = Int(arc4random_uniform(UInt32(i + 1)))
(self[i], self[j]) = (self[j], self[i])
}
}
}
Note: A more concise solution in Swift is possible from iOS10 using GameplayKit.
Note: An algorithm for unstable shuffling (with all positions forced to change if count > 1) is also available
This is the simplest and fastest way to shuffle NSArrays or NSMutableArrays
(object puzzles is a NSMutableArray, it contains puzzle objects. I've added to
puzzle object variable index which indicates initial position in array)
int randomSort(id obj1, id obj2, void *context ) {
// returns random number -1 0 1
return (random()%3 - 1);
}
- (void)shuffle {
// call custom sort function
[puzzles sortUsingFunction:randomSort context:nil];
// show in log how is our array sorted
int i = 0;
for (Puzzle * puzzle in puzzles) {
NSLog(#" #%d has index %d", i, puzzle.index);
i++;
}
}
log output:
#0 has index #6
#1 has index #3
#2 has index #9
#3 has index #15
#4 has index #8
#5 has index #0
#6 has index #1
#7 has index #4
#8 has index #7
#9 has index #12
#10 has index #14
#11 has index #16
#12 has index #17
#13 has index #10
#14 has index #11
#15 has index #13
#16 has index #5
#17 has index #2
you may as well compare obj1 with obj2 and decide what you want to return
possible values are:
NSOrderedAscending = -1
NSOrderedSame = 0
NSOrderedDescending = 1
From iOS 10, you can use NSArray shuffled() from GameplayKit. Here is an helper for Array in Swift 3:
import GameplayKit
extension Array {
#available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
func shuffled() -> [Element] {
return (self as NSArray).shuffled() as! [Element]
}
#available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
mutating func shuffle() {
replaceSubrange(0..<count, with: shuffled())
}
}
There is a nice popular library, that has this method as it's part, called SSToolKit in GitHub.
File NSMutableArray+SSToolkitAdditions.h contains shuffle method. You can use it also. Among this, there seem to be tons of useful things.
The main page of this library is here.
If you use this, your code will be like this:
#import <SSCategories.h>
NSMutableArray *tableData = [NSMutableArray arrayWithArray:[temp shuffledArray]];
This library also has a Pod (see CocoaPods)
If elements have repeats.
e.g. array: A A A B B or B B A A A
only solution is: A B A B A
sequenceSelected is an NSMutableArray which stores elements of class obj, which are pointers to some sequence.
- (void)shuffleSequenceSelected {
[sequenceSelected shuffle];
[self shuffleSequenceSelectedLoop];
}
- (void)shuffleSequenceSelectedLoop {
NSUInteger count = sequenceSelected.count;
for (NSUInteger i = 1; i < count-1; i++) {
// Select a random element between i and end of array to swap with.
NSInteger nElements = count - i;
NSInteger n;
if (i < count-2) { // i is between second and second last element
obj *A = [sequenceSelected objectAtIndex:i-1];
obj *B = [sequenceSelected objectAtIndex:i];
if (A == B) { // shuffle if current & previous same
do {
n = arc4random_uniform(nElements) + i;
B = [sequenceSelected objectAtIndex:n];
} while (A == B);
[sequenceSelected exchangeObjectAtIndex:i withObjectAtIndex:n];
}
} else if (i == count-2) { // second last value to be shuffled with last value
obj *A = [sequenceSelected objectAtIndex:i-1];// previous value
obj *B = [sequenceSelected objectAtIndex:i]; // second last value
obj *C = [sequenceSelected lastObject]; // last value
if (A == B && B == C) {
//reshufle
sequenceSelected = [[[sequenceSelected reverseObjectEnumerator] allObjects] mutableCopy];
[self shuffleSequenceSelectedLoop];
return;
}
if (A == B) {
if (B != C) {
[sequenceSelected exchangeObjectAtIndex:i withObjectAtIndex:count-1];
} else {
// reshuffle
sequenceSelected = [[[sequenceSelected reverseObjectEnumerator] allObjects] mutableCopy];
[self shuffleSequenceSelectedLoop];
return;
}
}
}
}
}
NSUInteger randomIndex = arc4random() % [theArray count];
Kristopher Johnson's answer is pretty nice, but it's not totally random.
Given an array of 2 elements, this function returns always the inversed array, because you are generating the range of your random over the rest of the indexes. A more accurate shuffle() function would be like
- (void)shuffle
{
NSUInteger count = [self count];
for (NSUInteger i = 0; i < count; ++i) {
NSInteger exchangeIndex = arc4random_uniform(count);
if (i != exchangeIndex) {
[self exchangeObjectAtIndex:i withObjectAtIndex:exchangeIndex];
}
}
}
Edit: This is not correct. For reference purposes, I did not delete this post. See comments on the reason why this approach is not correct.
Simple code here:
- (NSArray *)shuffledArray:(NSArray *)array
{
return [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
if (arc4random() % 2) {
return NSOrderedAscending;
} else {
return NSOrderedDescending;
}
}];
}
Related
I get an error message when I try to sort an array of one hundred thousand ints(I've tested the sort and it works for fifty thousand):
warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available.
I also have the compare method iteratively and the same error appears
Why is this error message happening?
Is it possible to sort that list and if so how to fix it?
-(void) quickSort{
return [self quickSort:0 pivot:[self.toSort count]-1 right: [self.toSort count]-1];
}
-(void) quickSort:(int) left pivot:(int) pivot right:(int) right {
if(left < right){
pivot = [self compareToPivot:[[self.toSort objectAtIndex:right] intValue] start:left finish:right position:left];
[self quickSort:pivot+1 pivot:pivot right:right];
[self quickSort:left pivot:pivot right:pivot-1];
}
}
-(int) compareToPivot:(int) pivot start:(int)start finish:(int)finish position:(int)pos{
if(pos == finish){
[self switchNums:start second:finish];
return start;
}
if([[self.toSort objectAtIndex:pos] intValue] <= pivot){
[self switchNums:pos second:start];
return [self compareToPivot:pivot start:start+1 finish:finish position:pos+1];
}
return [self compareToPivot:pivot start:start finish:finish position:pos+1];
}
-(void) switchNums:(int)first second:(int)second{
id temp = [self.toSort objectAtIndex:second];
[self.toSort replaceObjectAtIndex:second withObject:[self.toSort objectAtIndex:first]];
[self.toSort replaceObjectAtIndex:first withObject:temp];
}
Iterative Compare and this runs fine:
-(int) compareToPivot:(int) pivot start:(int)start finish:(int)finish position:(int)pos{
while(pos != finish){
if([[self.toSort objectAtIndex:pos] intValue] <= pivot){
[self switchNums:pos second:start];
start+=1;
}
pos++;
}
[self switchNums:start second:finish];
return start;
}
While Quicksort itself is considered a recursive algorithm, the partition step (your comparetoPivot method) is not meant for recursion. And your implementation of this method is not only recursive, but it also is O(N) as far as stack space is concerned. You only recurse with one less element than before with each recursion into compareToPivot. Blowing up (running out stack) at around 100K elements sounds is to be expected as the default stack is around 500KB.
I used your question as an excuse to practice my Obj-C, which I'm a bit rusty on. But here's the implementation of recursive Quicksort straight out of the classic Algorithms (Cormen et. al.) book and adapted for your toSort array. I haven't tested it all out yet, but you can certainly give it a whirl.
-(int)partition: (NSMutableArray*)arr pivot:(int)pivot right:(int)right
{
int x = [[arr objectAtIndex: pivot] intValue];
int i = pivot;
int j = right;
while (true)
{
while ([[arr objectAtIndex: j] intValue] > x)
{
j--;
}
while ([[arr objectAtIndex: i] intValue] < x)
{
i++;
}
if (i < j) {
id objI = [arr objectAtIndex: i];
id objJ = [arr objectAtIndex: j];
[arr replaceObjectAtIndex:i withObject:objJ];
[arr replaceObjectAtIndex:j withObject:objI];
j--;
i++;
}
else
{
return j;
}
}
}
-(void)quickSort
{
int len = (int)[self.toSort count];
[self quicksort:self.toSort left:0 right:(len-1)];
}
-(void)quicksort: (NSMutableArray*)arr left:(int)left right:(int)right
{
if (left< right)
{
int q = [self partition:arr pivot:left right:right];
[self quicksort: arr left:left right:q];
[self quicksort: arr left:(q+1) right:right];
}
}
I'm writing a category on NSArray to add JavaScript array methods to NSArray. In JavaScript, the splice() method both adds/removes items to/from an array. But the number of objects added to the array may vary. So I used va_list to allow for a more flexible input of object values.
As it stands the method requires a count input value. How could I rewrite this without one?
Interface
#interface NSArray (JavaScriptArray)
- (NSArray *)splice:(NSUInteger)index remove:(NSUInteger)remove count:(NSUInteger)count arguments:(id)firstObject,...;
#end
Implementation
#implementation NSArray (JavaScriptArray)
- (NSArray *)splice:(NSUInteger)index remove:(NSUInteger)remove count:(NSUInteger)count arguments:(id)firstObject,...
{
NSMutableArray *mSplice = [NSMutableArray arrayWithArray:self];
if (remove != 0) {
NSUInteger removeIndex = index;
for (NSUInteger i = 0; i < remove; i++) {
[mSplice removeObjectAtIndex:removeIndex];
removeIndex = removeIndex + 1;
}
}
if (count != 0) {
NSUInteger addIndex = index;
id eachObject;
va_list argumentList;
if (firstObject) {
[mSplice insertObject:firstObject atIndex:addIndex];
addIndex = addIndex + 1;
va_start(argumentList, firstObject);
eachObject = va_arg(argumentList, id);
for (NSUInteger i = 0; i < count; i++) {
[mSplice insertObject:eachObject atIndex:addIndex];
addIndex = addIndex + 1;
}
va_end(argumentList);
}
}
return [NSArray arrayWithArray:mSplice];
}
#end
Calling the Method
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *fruit = #[#"Banana", #"Orange", #"Apple", #"Mango"];
NSArray *fruitSplice = [fruit splice:2 remove:0 count:4 arguments:#"Lemon", #"Kiwi", #"Kiwi", #"Kiwi"];
NSLog(#"fruitSplice %#", fruitSplice);
}
#end
Debugger Window
fruitSplice (
Banana,
Orange,
Lemon,
Kiwi,
Kiwi,
Kiwi,
Kiwi,
Apple,
Mango
)
Removing the count argument is no problem, because actually your "add" loop appears to be incorrect. After you've gotten the second item from the va_list with eachObject = va_arg(argumentList, id);, you never get another object. The only reason your example works is that all the later items are the same: #"Kiwi". If your test call was
NSArray *fruitSplice = [fruit splice:2
remove:0
count:4
arguments:#"Lemon", #"Albatross", #"Kiwi", #"Kiwi"];
you'd see
fruitSplice (
Banana,
Orange,
Lemon,
Albatross,
Albatross,
Albatross,
Albatross,
Apple,
Mango
)
as output.
You need to redo your unpacking of the va_list, and you can keep your own counter while you're iterating it, but the catch is that there has to be a sentinel value: an value that can't possibly appear as a valid list value, that indicates you've come to the end. For object-type variadic arguments you would generally use nil as the sentinel.
When you're using a va_list you must have either a sentinel or a count. There's no other way for you to know when to stop popping arguments.
Your signature can become*:
- (NSArray *)KRSpliceAt:(NSUInteger)index
removingCount:(NSUInteger)remove
addingObjects:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION;
The NS_REQUIRES_NIL_TERMINATION is strictly optional, but will make the compiler notify you if the method is called without a sentinel.
Then your adding loop changes:
// Insertion index starts at given splice point
NSUInteger addIndex = index;
// Initialize the va_list
va_list objs;
va_start(objs, firstObj);
// Start at the beginning
id nextObj = firstObj;
// Test for sentinel nil
while( nextObj ){
[mSplice insertObject:nextObj atIndex:addIndex];
// Update insertion point
addIndex++;
// Get next argument
nextObj = va_arg(objs, id);
}
// Signal completion of list
va_end(objs);
*Methods you add to classes you don't own should always be prefixed. It's a bit annoying, but it's good practice to prevent a catastrophic clash if you should happen to pick the same name as another method.
I'm initializing a C array of objects and setting the first element:
id __strong *_objs = (id __strong *)calloc(16,sizeof(*_objs));
_objs[0] = #1;
_count++;
Then I'm using the following implementation of NSFastEnumeration:
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (id __unsafe_unretained*)stackbuf
count: (NSUInteger)len
{
NSUInteger size = _count;
NSInteger count;
state->mutationsPtr = (unsigned long *)size;
count = MIN(len, size - state->state);
if (count > 0)
{
IMP imp = [self methodForSelector: #selector(objectAtIndex:)];
int p = state->state;
int i;
for (i = 0; i < count; i++, p++) {
stackbuf[i] = (*imp)(self, #selector(objectAtIndex:), p);
}
state->state += count;
}
else
{
count = 0;
}
state->itemsPtr = stackbuf;
return count;
}
Unfortunately it crashes with EXC_BAD_ACCESS when I run it:
for (id object in array){ // EXC_BAD_ACCESS
NSLog(#"%#",object)
}
Any idea why?
If you have CodeRunner, here is an executable version.
The problem is the mutationsPtr which points to the memory address 1 which you are not allowed to access (and which is not 4 byte aligned as well):
state->mutationsPtr = (unsigned long *)size;
Replace it with a valid pointer for starters (careful: the one below may make no sense at all in your scenario, but at least it fixes the EXC_BAD_ACCESS):
state->mutationsPtr = (unsigned long *)&_count;
#Jano
In case you want to get rid of the compiler warning you will get with recent versions of Xcode (4.6) for
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (id __unsafe_unretained*)stackbuf
count: (NSUInteger)len
because it does not match the original prototype for objects:..stackbuf
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (__autoreleasing id *)stackbuf
count: (NSUInteger)len
see Todd Lehmans answer in Automatic Reference Counting: Error with fast enumeration
I have a NSMutableArray called putNumberUsed. It contains the following objects #"blah1,#"blah2",#"blah3",#"blah4". I want to shuffle these objects randomly so for example if I chose:
[putNumberUsed objectAtIndex:0]
it would give me anything but "blah1". How would I go about doing this? The following is the code I used thus far:
NSMutableArray *putNumbersUsed = [[NSMutableArray alloc] arrayWithObjects:#"blah1",#"blah2",#"blah3",#"blah4",nil];
I think, You can write a loop for that. Please check the following code,
for (int i = 0; i < putNumberUsed.count; i++) {
int randomInt1 = arc4random() % [putNumberUsed count];
int randomInt2 = arc4random() % [putNumberUsed count];
[putNumberUsed exchangeObjectAtIndex:randomInt1 withObjectAtIndex:randomInt2];
}
I this this may be useful to you.
Here is a shuffling solution with all positions forced to change when count > 1.
Add a category like NSMutableArray+Shuffle.m:
#implementation NSMutableArray (Shuffle)
// Fisher-Yates shuffle variation with all positions forced to change
- (void)unstableShuffle
{
for (NSInteger i = self.count - 1; i > 0; i--)
// note: we use u_int32_t because `arc4random_uniform` doesn't support int64
[self exchangeObjectAtIndex:i withObjectAtIndex:arc4random_uniform((u_int32_t)i)];
}
#end
Then you can shuffle like:
[putNumbersUsed unstableShuffle];
This solution:
has no modulo bias
has no naive bias
has no sorting bias
A Swift 3.2 and Swift 4 equivalent is:
extension Array {
mutating func unstableShuffle() {
for i in stride(from: count - 1, to: 0, by: -1) {
swapAt(i, Int(arc4random_uniform(UInt32(i))))
}
}
}
A Swift 3.0 and 3.1 equivalent is:
extension Array {
mutating func unstableShuffle() {
for i in stride(from: count - 1, to: 0, by: -1) {
swap(&self[i], &self[Int(arc4random_uniform(UInt32(i)))])
}
}
}
Note: An algorithm for regular shuffling (where a result with same positions being possible) is also available
From iOS 10.x++ new concept of shuffle array is given by Apple,
You need to import the framework :
ObjeC
#import <GameplayKit/GameplayKit.h>
NSArray *shuffledArray = [yourArray shuffledArray];
Swift
import GameplayKit
let shuffledArray = yourArray.shuffled()
You can shuffle the object by using the following line of code,
[putNumbersUsed exchangeObjectAtIndex:3 withObjectAtIndex:0];
I think this may useful to you.
generate a random number for index
int randomInt = arc4random() % [putNumberUsed count];
[putNumberUsed objectAtIndex:randomInt];
Use this:
for (int i = 0; i < [putNumberUsed count]; i++) {
int random = arc4random() % [putNumberUsed count];
[putNumbersUsed exchangeObjectAtIndex:random withObjectAtIndex:i];
}
I have an object, and I want to list all the selectors to which it responds. It feels like this should be perfectly possible, but I'm having trouble finding the APIs.
This is a solution based on the runtime C functions:
class_copyMethodList returns a list of class methods given a Class object obtainable from an object.
#import <objc/runtime.h>
[..]
SomeClass * t = [[SomeClass alloc] init];
int i=0;
unsigned int mc = 0;
Method * mlist = class_copyMethodList(object_getClass(t), &mc);
NSLog(#"%d methods", mc);
for(i=0;i<mc;i++)
NSLog(#"Method no #%d: %s", i, sel_getName(method_getName(mlist[i])));
/* note mlist needs to be freed */
I think usually you'll want to do that in the console, instead of cluttering your code with debug code. This is how you can do that while debugging in lldb:
(Assuming an object t)
p int $num = 0;
expr Method *$m = (Method *)class_copyMethodList((Class)object_getClass(t), &$num);
expr for(int i=0;i<$num;i++) { (void)NSLog(#"%s",(char *)sel_getName((SEL)method_getName($m[i]))); }
This is also possible with Swift:
let obj = NSObject()
var mc: UInt32 = 0
let mcPointer = withUnsafeMutablePointer(&mc, { $0 })
let mlist = class_copyMethodList(object_getClass(obj), mcPointer)
print("\(mc) methods")
for i in 0...Int(mc) {
print(String(format: "Method #%d: %s", arguments: [i, sel_getName(method_getName(mlist[i]))]))
}
Output:
251 methods
Method #0: hashValue
Method #1: postNotificationWithDescription:
Method #2: okToNotifyFromThisThread
Method #3: fromNotifySafeThreadPerformSelector:withObject:
Method #4: allowSafePerformSelector
Method #5: disallowSafePerformSelector
...
Method #247: isProxy
Method #248: isMemberOfClass:
Method #249: superclass
Method #250: isFault
Method #251: <null selector>
Tested with the 6s simulator running iOS 9.2, Xcode Version 7.2 (7C68).
Taking inspiration from JAL's answer, in Swift you can do:
extension NSObject {
var __methods: [Selector] {
var methodCount: UInt32 = 0
guard
let methodList = class_copyMethodList(type(of: self), &methodCount),
methodCount != 0
else { return [] }
return (0 ..< Int(methodCount))
.flatMap({ method_getName(methodList[$0]) })
}
}
ARC realization
SomeClass *someClass = [[SomeClass alloc] init];
//List of all methods
unsigned int amountMethod = 0;
Method *methods = class_copyMethodList(someClass, &amountMethod);
for (unsigned int i = 0; i < amountMethod; i++) {
Method method = methods[i];
printf("\t method named:'%s' \n", sel_getName(method_getName(method)));
}
free(methods);
Something like this should work (just put it in the object you're curious about). For example if you have an object that's a delegate and want to know what 'hooks' are available this will print out messages to give you that clue:
-(BOOL) respondsToSelector:(SEL)aSelector {
printf("Selector: %s\n", [NSStringFromSelector(aSelector) UTF8String]);
return [super respondsToSelector:aSelector];
}
Note that I discovered this in the iPhone Developer's Cookbook so I can't take credit! For example output I get from a UIViewController that implements the protocols <UITableViewDelegate, UITableViewDataSource>:
Selector: tableView:numberOfRowsInSection:
Selector: tableView:cellForRowAtIndexPath:
Selector: numberOfSectionsInTableView:
Selector: tableView:titleForHeaderInSection:
Selector: tableView:titleForFooterInSection:
Selector: tableView:commitEditingStyle:forRowAtIndexPath:
Selector: sectionIndexTitlesForTableView:
Selector: tableView:sectionForSectionIndexTitle:atIndex:
...
...
etc.,etc.
If you want to also get the selectors for the super classes you can loop through like this:
Class c = [myObject class];
while (c != nil) {
int i = 0;
unsigned int mc = 0;
Method* mlist = class_copyMethodList(c, &mc);
NSLog(#"%d methods for %#", mc, c);
for(i = 0; i < mc; i++) {
const char* selName = sel_getName(method_getName(mlist[i]));
NSLog(#"Method #%d: %s", i, selName);
}
free(mlist);
c = [c superclass];
}