11

When you print a NSThread's description, you get something like this:

<NSThread: 0x1e511b70>{name = (null), num = 1}

Is this "num" available somehow?

This is for debugging only, so it does not need to clear Apple's approval process.

Steven Fisher
  • 44,462
  • 20
  • 138
  • 192
  • Maybe it's in `-[ threadDictionary]`? (You can store thread-local information in `NSThread`'s _threadDictionary_...) – nielsbot Mar 21 '13 at 21:27
  • Great idea, but no dice: It's empty. :) – Steven Fisher Mar 21 '13 at 21:30
  • Isn't that just its pointer? May not be the same as the thread ID that NSLog prints. – Peter Hosey Mar 21 '13 at 21:39
  • No, NSLog prints something much prettier. I could stick with the pointer, of course, but I'd like to find the number. (For instance, the main thread is 1.) – Steven Fisher Mar 21 '13 at 21:41
  • So guess it's just the order in which the thread was created out of all threads. You could patch `+[NSThread alloc]` to keep track of the number of threads created... (then retrieve this information via a category on `NSThread`) – nielsbot Mar 21 '13 at 21:48
  • 1
    AFAIK, it can only be accessed from `[thread description]` and extract the number from it – Bryan Chen Mar 21 '13 at 21:49
  • oh yeah--you could parse the result from `[thread description]` – nielsbot Mar 21 '13 at 21:49
  • Oh, for some reason I thought you were talking about the `0x1e511b70` that's highlighted in red (I wonder what language SO thought that line was in), not the `num` key in the dictionary. Sorry. – Peter Hosey Mar 21 '13 at 21:57
  • Ah, that's just Stack Overflow's syntax highlighting. I should have been more specific given it did that, though. – Steven Fisher Mar 21 '13 at 22:01
  • WARNING: I was parsing the description to get the number (for debugging purposes as well). My code broke in iOS 8 because the description format changed from... {**num** = 1, name = main} ...to... {**number** = 1, name = main} – Dave Owens Sep 12 '14 at 22:33
  • ANOTHER WARNING: It's worse than I originally thought... "num" changed to "number" and they also changed the order of number and name. – Dave Owens Sep 12 '14 at 23:53

2 Answers2

15

That number is actually an ivar in NSThread's private implementation class. The class is _NSThreadInternal, and its name is "_private". Inside that object, the ivar is seqNum.

You can pull it directly if you're willing to rely on undocumented key paths. This'll do it (and good call neilsbot on using valueForKeyPath instead of runtime calls):

@implementation NSThread (GetSequenceNumber)

- (NSInteger)sequenceNumber
{
    return [[self valueForKeyPath:@"private.seqNum"] integerValue];
}

@end

I tested it by manually setting that ivar with runtime calls and then NSLogging the thread. Sure enough, the description reflected the change. This is obviously not documented, so...

...use at your own risk.

It's a fun exercise, but things are typically private for a reason. Shipped code should certainly avoid things like this unless all other routes have been thoroughly exhausted.

Matt Wilding
  • 20,115
  • 3
  • 67
  • 95
7

I went ahead and wrote out @xlc's suggestion, just because:

@implementation NSThread (ThreadGetIndex)

-(NSInteger)getThreadNum
{
    NSString * description = [ self description ] ;
    NSArray * keyValuePairs = [ description componentsSeparatedByString:@"," ] ;
    for( NSString * keyValuePair in keyValuePairs )
    {
        NSArray * components = [ keyValuePair componentsSeparatedByString:@"=" ] ;
        NSString * key = components[0] ;
        key = [ key stringByTrimmingCharactersInSet:[ NSCharacterSet whitespaceCharacterSet ] ] ;
        if ( [ key isEqualToString:@"num" ] )
        {
            return [ components[1] integerValue ] ;
        }
    }
    @throw @"couldn't get thread num";
    return -1 ;
}

@end

This answers the question of getting "num" from the thread--although the question linked as a dupe might be helpful for the general question of uniquely identifying threads.

(The answer I like there is "generate a UUID and put in in the thread's thread dictionary.)

nielsbot
  • 15,922
  • 4
  • 48
  • 73
  • I like this better in this case, as the thread number is more readable than a UUID, and this matches the debugger. Thanks. – Steven Fisher Mar 21 '13 at 21:59
  • if you're doing this a lot, you can modify this code to cache the lookup using `objc_setAssociatedObject()`/`objc_getAssociatedObject()` – nielsbot Mar 21 '13 at 23:19