187

I am implementing push notifications. I'd like to save my APNS Token as a String.

- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken
{
    NSString *tokenString = [NSString stringWithUTF8String:[newDeviceToken bytes]]; //[[NSString alloc]initWithData:newDeviceToken encoding:NSUTF8StringEncoding];
    NSLog(@"%@", tokenString);
    NSLog(@"%@", newDeviceToken);
}

The first line of code prints null. the second prints the token. How can I get my newDeviceToken as an NSString?

mfaani
  • 33,269
  • 19
  • 164
  • 293
Sheehan Alam
  • 60,111
  • 124
  • 355
  • 556

31 Answers31

269

If anyone is looking for a way to do this in Swift:

Swift 3 introduces the Data type, with value semantics. To convert the deviceToken to a String, you can do as follows:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
    print(token)
}

Old answer using NSData:

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
    let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
    var tokenString = ""

    for i in 0..<deviceToken.length {
        tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
    }

    print("tokenString: \(tokenString)")
}
mfaani
  • 33,269
  • 19
  • 164
  • 293
Sascha
  • 5,903
  • 3
  • 24
  • 20
  • Error on the first line inside the function : Cannot convert expression's type 'UnsafePointer' to type 'ST2' – Cherif Mar 03 '15 at 13:48
  • @Cherif: Just updated the code for the latest version of Swift – Sascha Mar 03 '15 at 21:36
  • 140
    Why does this have to be so complicated, what's wrong with the OS giving us a string since that is what everyone needs ? Thank you for this solution. – Piwaf Jun 19 '15 at 18:28
  • 1
    Thanks for providing a Swift solution. Worked perfectly! – Justin Thiele Jun 23 '15 at 03:30
  • 3
    @Sascha I hope you approve of my edit to your very useful answer :) – jrturton Jan 14 '16 at 20:35
  • 1
    @jrturton absolutely. Thanks! – Sascha Jan 18 '16 at 09:46
  • 16
    I refactored: `let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()` http://qiita.com/mono0926/items/3cf0dca3029f32f54a09 – mono Sep 22 '16 at 05:58
  • 2
    I don't recommend using .description as that is not guaranteed to be stable. Check out my answer here: http://stackoverflow.com/questions/9372815/how-can-i-convert-my-device-token-nsdata-into-an-nsstring/39754930#39754930 – swift taylor Sep 28 '16 at 19:45
  • NB @MasayukiOno code should be enclosed in an extension of Data i.e. extension Data { let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() } – wuf810 Jan 10 '17 at 11:07
  • I would have gladly stayed in Swift 2 for time reasons but was forced to migrate, then there's all these new issues to consider, wish Apple would respect its developers. – Jim109 Apr 13 '17 at 17:02
  • following my test in the answers the fastest as of 05.12.2017 is deviceToken.reduce("", {$0 + String(format: "%02x", $1)}) – Nicolas Manzini May 12 '17 at 10:05
  • what does this format '02.2' do? it seems work without them. – gabbler Jun 08 '17 at 08:04
  • 10
    Can you explain what does `"%02.2hhx` do? – mfaani Nov 14 '17 at 17:05
  • 1
    Those who choosing between what to use, there is a sample: `var token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()` // gives like 7cbac37b00275289a2e21c357241b615e6939e0dda7daf4feb537fce6ee61760; `token = deviceToken?.reduce("", {$0 + String(format: "%02X", $1)})` // gives like 7CBAC37B00275289A2E21C357241B615E6939E0DDA7DAF4FEB537FCE6EE61760 – Nike Kov Jun 11 '18 at 10:18
164

Someone Helped me with this.I am just passing along

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {

    const unsigned *tokenBytes = [deviceToken bytes];
    NSString *hexToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                         ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                         ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                         ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];

    [[MyModel sharedModel] setApnsToken:hexToken];
}
pkamb
  • 33,281
  • 23
  • 160
  • 191
Shubhank
  • 21,721
  • 8
  • 65
  • 83
  • 5
    This is the best solution, since encondig bytes as hex, implies that you can count it ;) – loretoparisi Sep 14 '12 at 12:56
  • 4
    On XCode 5 I had to cast the deviceToken to make it compile: const unsigned *tokenBytes = (const unsigned *)[deviceToken bytes]; – Ponytech Oct 06 '13 at 21:15
  • um.. what's the point of converting it to hex? why not just save it as is? – abbood Jul 04 '14 at 06:58
  • I mean in ray wenderlich's [tutorial](http://www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1) about sending push notifications, you simply copy the value of the device token from the iOS app and feed it to the push server as is, without any fancy pants hex conversion and all that stuff.. – abbood Jul 04 '14 at 07:01
  • Curious, why do you use ntohl? – jasongregori Aug 05 '14 at 20:41
  • @abbood some push servers consume an NSString (without spaces) instead of NSData. – weienw Oct 07 '14 at 03:45
  • why's it being declared as `const`? – Ian Dundas Oct 27 '14 at 09:39
  • @IanDundas because `[deviceToken bytes]` returns a `const unsigned *` – Matt Mar 19 '15 at 13:44
  • Error: Cannot initialize a variable of type 'const unsigned int *' with an rvalue of type 'const void *' – Jonny Mar 31 '15 at 08:02
  • 3
    Tokens are going to be larger than 32 bytes soon so this will need to be a loop over each byte, instead of eight hard-coded integers. – Tom Dalling Oct 28 '15 at 04:56
  • 5
    Would this be a better solution? `const unsigned *tokenBytes = [deviceToken bytes]; NSMutableString *hexToken = [NSMutableString string]; for (NSUInteger byteCount = 0; byteCount * 4 < [deviceToken length]; byteCount++) { [hexToken appendFormat:@"%08x", ntohl(tokenBytes[byteCount])]; }` – Harro Mar 23 '16 at 14:52
  • 9
    `Important: APNs device tokens are of variable length. Do not hard-code their size.` Apple says. – erkanyildiz Oct 18 '16 at 01:56
  • how to write this code in swift? I have objective c project and need to convert it to swift ... – Yestay Muratov Jun 13 '17 at 07:05
  • 1
    this is madness – Damian Rzeszot Sep 27 '17 at 12:11
154

You could use this

- (NSString *)stringWithDeviceToken:(NSData *)deviceToken {
    const char *data = [deviceToken bytes];
    NSMutableString *token = [NSMutableString string];

    for (NSUInteger i = 0; i < [deviceToken length]; i++) {
        [token appendFormat:@"%02.2hhX", data[i]];
    }

    return [token copy];
}
Marcus Adams
  • 53,009
  • 9
  • 91
  • 143
Vlad Polyanskiy
  • 2,589
  • 2
  • 18
  • 21
42

For those who want in Swift 3 and most easier method

func extractTokenFromData(deviceToken:Data) -> String {
    let token = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
    return token.uppercased();
}
Anand
  • 5,323
  • 5
  • 44
  • 58
  • 1
    I wrote the same code :) This is most swifty version, and only this works – Quver Oct 10 '16 at 20:14
  • 1
    @Anand can u please explain what is happing in this code `deviceToken.reduce("", {$0 + String(format: "%02X", $1)})` – Ramakrishna Apr 19 '17 at 06:54
  • 1
    It uses reduce function of swift that serialises Data into hexadecimal string and then to String. To understand more about reduce function read https://useyourloaf.com/blog/swift-guide-to-map-filter-reduce/ – Anand Apr 19 '17 at 13:11
33

Note - This will not work when compiling with the iOS 13 or later SDK

use this :

NSString * deviceTokenString = [[[[deviceToken description]
                         stringByReplacingOccurrencesOfString: @"<" withString: @""] 
                        stringByReplacingOccurrencesOfString: @">" withString: @""] 
                       stringByReplacingOccurrencesOfString: @" " withString: @""];
        
NSLog(@"The generated device token string is : %@",deviceTokenString);
Mark Reid
  • 2,611
  • 3
  • 23
  • 45
kulss
  • 2,057
  • 1
  • 14
  • 16
  • 139
    It seems a bad idea to use description : nothing ensures that later version of iOS will not change the implementation and result of this call. – madewulf Nov 14 '12 at 14:00
  • 18
    Indeed, this is a really bad idea. – David Snabel-Caunt Sep 24 '13 at 15:59
  • 21
    @madewulf very nice of you to point out how it's such a terrible idea to use description.. it would have been even nicer if you have suggested an alternative – abbood Jul 04 '14 at 06:54
  • 6
    The solution here under with [deviceToken bytes] fits the bill. – madewulf Jul 31 '14 at 15:30
  • 3
    Why would Apple change this, its ok to use this kind of implementation. – Jakub Truhlář Sep 09 '15 at 10:21
  • 1
    This should be the accepted answer: http://stackoverflow.com/a/16411517/1555903 Swift version: http://stackoverflow.com/a/24979958/1555903 – klaaspieter Jan 12 '16 at 09:59
  • 39
    Turns out as of Swift 3/iOS 10, .description on a device token returns "32 bytes". So yeah, don't use this. – Victor Luft Sep 13 '16 at 17:04
  • This method no longer works, use the new updated version using bytes. – Pedro Góes Nov 24 '18 at 04:19
  • 5
    As of iOS 13, the behavior of `[NSData description]` has changed and this code will generate an invalid token string. Please use [this answer](https://stackoverflow.com/questions/9372815/how-can-i-convert-my-device-token-nsdata-into-an-nsstring/24979958#24979958) – waltflanagan Jul 04 '19 at 14:57
  • 2
    Indeed, here are some thread in Apple forums describing the `description` change in iOS 13. [here](https://forums.developer.apple.com/thread/119111) and [here](https://forums.developer.apple.com/thread/117545) – CJ Lin Jul 23 '19 at 17:12
  • Developers shouldn’t have relied on a specific format for an object’s description.As it is can change in any version. – SuryaKantSharma Sep 19 '19 at 06:30
  • 1
    Some trainee used this exact same reply in our app earlier this year, and building on iOS 13 just broke it. I don't understand why this was ever upvoted, it's clearly an ugly, brittle hack. – Guillaume Laurent Oct 08 '19 at 15:49
  • This is not the right solution as already pointed out. The "description" of an object is not consistent and should not be used as a serialization method. – Daniel Rochetti Oct 09 '19 at 17:48
  • This is the first result on Google when searching "push token to string"... This really should not be the accepted answer. It also breaks on iOS 13 with apps built with Xcode 10.3. – Alexandre Blin Oct 11 '19 at 12:11
  • Not worked in ios 13. Vishnu prakash answer is perfect. – Manish Nov 29 '19 at 06:33
  • @madewulf Was right 4 years back. – Sandeep Rana Feb 25 '22 at 18:25
26

Explanation of %02.2hhx in the high vote answer:

  • %: Introduces the x conversion specifier.
  • 02: The minimum width of the converted value is 2. If the converted value has fewer bytes than the field width, it shall be padded with 0 on the left.
  • .2: Gives the minimum number of digits to appear for the x conversion specifier.
  • hh: Specifies that the x conversion specifier applies to a signed char or unsigned char argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to signed char or unsigned char before printing).
  • x: The unsigned argument shall be converted to unsigned hexadecimal format in the style "dddd"; the letters "abcdef" are used. The precision specifies the minimum number of digits to appear; if the value being converted can be represented in fewer digits, it shall be expanded with leading zeros. The default precision is 1. The result of converting zero with an explicit precision of zero shall be no characters.

For more details, see the IEEE printf specification.


Based on the above explanation, I think it is better to change %02.2hhx to %02x or %.2x.

For Swift 5, the following methods are all feasible:

deviceToken.map({String(format: "%02x", $0)}).joined()
deviceToken.map({String(format: "%.2x", $0)}).joined()
deviceToken.reduce("", {$0 + String(format: "%02x", $1)})
deviceToken.reduce("", {$0 + String(format: "%.2x", $1)})

The test is as follows:

let deviceToken = (0..<32).reduce(Data(), {$0 + [$1]})
print(deviceToken.reduce("", {$0 + String(format: "%.2x", $1)}))
// Print content:
// 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
jqgsninimo
  • 6,562
  • 1
  • 36
  • 30
17

In iOS 13 the description will be in different format. Kindly use below code to fetch the device token.

- (NSString *)fetchDeviceToken:(NSData *)deviceToken {
    NSUInteger len = deviceToken.length;
    if (len == 0) {
        return nil;
    }
    const unsigned char *buffer = deviceToken.bytes;
    NSMutableString *hexString  = [NSMutableString stringWithCapacity:(len * 2)];
    for (int i = 0; i < len; ++i) {
        [hexString appendFormat:@"%02x", buffer[i]];
    }
    return [hexString copy];
}
Fattie
  • 27,874
  • 70
  • 431
  • 719
Vishnu Prakash
  • 189
  • 1
  • 4
  • Perfect solution for ios 13. Thanks Vishnu – Manish Nov 29 '19 at 06:32
  • 1
    It doesn't compile currently - `length` in the for loop should be changed to `len`. Apparently a too small change for me to make an edit.. But else works perfectly! – Anders Friis Dec 19 '19 at 15:07
13

It's my solution and It works well in my app:

    NSString* newToken = [[[NSString stringWithFormat:@"%@",deviceToken] 
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]] stringByReplacingOccurrencesOfString:@" " withString:@""];
  • convert NSData to NSString with stringWithFormat
  • trim the "<>"
  • remove the spaces
Zeb
  • 1,715
  • 22
  • 34
  • 11
    This just implicitly calls `-description`, so it isn't any safer than the accepted answer. – jszumski Nov 10 '14 at 20:59
  • Can you please link your source? I can't find information about it anywhere. Thx. – Zeb Nov 11 '14 at 22:36
  • Found it! I think that it is a little different. Use the description attribute directly is not safe because it could change in future versions, but if you use it THROUGH a NSString method you will hardly have problems. – Zeb Nov 11 '14 at 22:47
  • 6
    No this really calls `description` on deviceToken like jszumski says. – Jonny Mar 31 '15 at 08:00
  • Hi Jonny, probably you misunderstand what I said in my previous comment: the `description` method can change, but if you use it through another method it will be safe because "they" will adapt it. Btw, every solution here uses the `description` field, directly or not, so if you have a better solution, we will be very thankful. – Zeb Mar 31 '15 at 21:06
  • 1
    @Zeb It's not safe to rely on `description` whether you call it directly, or use it through another method, because the format of the returned string could be changed at any time. The correct solution is here: http://stackoverflow.com/a/16411517/108105 – Tom Dalling Oct 28 '15 at 05:00
11

I think converting deviceToken to hex byte string has no sense. Why? You will send it to your backend, where it will be transformed back to bytes to be pushed to APNS. So, use NSData's method base64EncodedStringWithOptions, push it to server, and then use reverse base64decoded data :) That is so much easier :)

NSString *tokenString = [tokenData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
JAL
  • 41,701
  • 23
  • 172
  • 300
Oleg Shanyuk
  • 1,296
  • 2
  • 15
  • 26
  • @jeet.chanchawat please do not add code to other users' answers. We don't want to put words in their mouth, especially when adding Swift to an Objective-C answer. Instead, add your own answer. – JAL Feb 06 '17 at 15:27
  • 2
    I just didn't wanted to plagiarise the @Oleg Shanyuk's answer. As it is just the translation in another language built upon his answer, So he deserves the future up votes. If I add another answer it will give me upvotes for the answer which is research of someone else. Hope this justifies the EDIT. – jeet.chanchawat Feb 07 '17 at 07:23
11

In iOS 13 description will break so use this

let deviceTokenString = deviceToken.map { String(format: "%02x", $0) }.joined()

For clarity, let’s break this down and explain each part:

The map method operates on each element of a sequence. Because Data is a sequence of bytes in Swift, the passed closure is evaluated for each byte in deviceToken. The String(format:) initializer evaluates each byte in the data (represented by the anonymous parameter $0) using the %02x format specifier, to produce a zero-padded, 2-digit hexadecimal representation of the byte / 8-bit integer. After collecting each byte representation created by the map method, joined() concatenates each element into a single string.

P.S don't use description gives different string in iOS 12 and iOS 13 and not safe as per future scope. Developers shouldn’t have relied on a specific format for an object’s description.

// iOS 12
(deviceToken as NSData).description // "<965b251c 6cb1926d e3cb366f dfb16ddd e6b9086a 8a3cac9e 5f857679 376eab7C>"

// iOS 13
(deviceToken as NSData).description // "{length = 32, bytes = 0x965b251c 6cb1926d e3cb366f dfb16ddd ... 5f857679 376eab7c }"

For more information read This.

SuryaKantSharma
  • 1,113
  • 12
  • 27
6

2020

token as text...

let tat = deviceToken.map{ data in String(format: "%02.2hhx", data) }.joined()

or if you prefer

let tat2 = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()

(result is the same)

Community
  • 1
  • 1
Fattie
  • 27,874
  • 70
  • 431
  • 719
3

This is a little bit shorter solution:

NSData *token = // ...
const uint64_t *tokenBytes = token.bytes;
NSString *hex = [NSString stringWithFormat:@"%016llx%016llx%016llx%016llx",
                 ntohll(tokenBytes[0]), ntohll(tokenBytes[1]),
                 ntohll(tokenBytes[2]), ntohll(tokenBytes[3])];
k06a
  • 17,755
  • 10
  • 70
  • 110
3

Functional Swift version

One liner:

let hexString = UnsafeBufferPointer<UInt8>(start: UnsafePointer(data.bytes),
count: data.length).map { String(format: "%02x", $0) }.joinWithSeparator("")

Here's in a reusable and self documenting extension form:

extension NSData {
    func base16EncodedString(uppercase uppercase: Bool = false) -> String {
        let buffer = UnsafeBufferPointer<UInt8>(start: UnsafePointer(self.bytes),
                                                count: self.length)
        let hexFormat = uppercase ? "X" : "x"
        let formatString = "%02\(hexFormat)"
        let bytesAsHexStrings = buffer.map {
            String(format: formatString, $0)
        }
        return bytesAsHexStrings.joinWithSeparator("")
    }
}

Alternatively, use reduce("", combine: +) instead of joinWithSeparator("") to be seen as a functional master by your peers.


Edit: I changed String($0, radix: 16) to String(format: "%02x", $0), because one digit numbers needed to having a padding zero

(I don't know yet how to mark a question as a duplicate of this other one, so I just posted my answer again)

Community
  • 1
  • 1
NiñoScript
  • 4,523
  • 2
  • 27
  • 33
2

Throwing my answer on the pile. Avoid using string parsing; It's not guaranteed by the docs that NSData.description will always work that way.

Swift 3 Implementation:

extension Data {
    func hexString() -> String {
        var bytesPointer: UnsafeBufferPointer<UInt8> = UnsafeBufferPointer(start: nil, count: 0)
        self.withUnsafeBytes { (bytes) in
            bytesPointer = UnsafeBufferPointer<UInt8>(start: UnsafePointer(bytes), count:self.count)
        }
        let hexBytes = bytesPointer.map { return String(format: "%02hhx", $0) }
        return hexBytes.joined()
    }
}
swift taylor
  • 610
  • 5
  • 10
2

This will work for you,

NSUInteger dataLength = deviceToken.length;
    
const unsigned char *dataBuffer = (const unsigned char *)deviceToken.bytes;
NSMutableString *deviceTokenString = [NSMutableString stringWithCapacity:(dataLength * 2)];
for (int i = 0; i < dataLength; ++i) {
    [deviceTokenString appendFormat:@"%02x", dataBuffer[i]];
}
    
NSLog(@"The generated device token string is : %@",deviceTokenString);
manishsharma93
  • 1,039
  • 1
  • 11
  • 26
1

I've tried to test two different methods with format "%02.2hhx" and "%02x"

    var i :Int = 0
    var j: Int = 0
    let e: Int = Int(1e4)
    let time = NSDate.timeIntervalSinceReferenceDate
    while i < e {
        _ =  deviceToken.map { String(format: "%02x", $0) }.joined()
        i += 1
    }
    let time2 = NSDate.timeIntervalSinceReferenceDate
    let delta = time2-time
    print(delta)

    let time3 = NSDate.timeIntervalSinceReferenceDate
    while j < e {
        _ =  deviceToken.reduce("", {$0 + String(format: "%02x", $1)})
        j += 1
    }
    let time4 = NSDate.timeIntervalSinceReferenceDate
    let delta2 = time4-time3
    print(delta2)

and the result is that the fastest is "%02x" at average 2.0 vs 2.6 for the reduced version:

deviceToken.reduce("", {$0 + String(format: "%02x", $1)})
Nicolas Manzini
  • 8,379
  • 6
  • 63
  • 81
1

Here's how you do it in Xamarin.iOS

public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
    var tokenStringBase64 = deviceToken.GetBase64EncodedString(NSDataBase64EncodingOptions.None);
    //now you can store it for later use in local storage
}
Drunken Daddy
  • 7,326
  • 14
  • 70
  • 104
  • I'm new to this but it looks like you need Hexadecimal when sending to APNS so I am not sure why you are suggesting base64... – Yepeekai Jun 23 '22 at 19:49
1

Using updateAccumulatingResult is more efficient than the various other approaches found here, so here's the Swiftiest way to stringify your Data bytes:

func application(_ application: UIApplication,
                 didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let token = deviceToken.reduce(into: "") { $0 += String(format: "%.2x", $1) }
    print(token)
}
Alex Curylo
  • 4,744
  • 1
  • 27
  • 37
0

For Swift :

var characterSet: NSCharacterSet = NSCharacterSet( charactersInString: "<>" )
    var deviceTokenString: String = ( deviceToken.description as NSString )
    .stringByTrimmingCharactersInSet( characterSet )
    .stringByReplacingOccurrencesOfString( " ", withString: "" ) as String

println( deviceTokenString )
Adarsh G J
  • 2,684
  • 1
  • 24
  • 25
0

2023

let tokenString = deviceToken.reduce("") { $0 + String(format: "%02.2hhx", $1) }

or:

let tokenString = deviceToken.map { String(format: "%02.2hhx", $0)}.joined()

To learn more about why the format 02.2hhx is suggested, you can read this post on NSHipster and the IEEE specification.

wzso
  • 3,482
  • 5
  • 27
  • 48
-1
NSString *tokenString = [[newDeviceToken description] stringByReplacingOccurrencesOfString:@"[<> ]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, [[newDeviceToken description] length])];
Genja Grishin
  • 122
  • 2
  • 6
  • great solution As of today, it can be implified to credentials.token.description.replacingOccurrences(of: "[<> ]", with: "", options: .regularExpression, range: nil) – Frank Aug 14 '16 at 00:41
-1

Swift:

let tokenString = deviceToken.description.stringByReplacingOccurrencesOfString("[ <>]", withString: "", options: .RegularExpressionSearch, range: nil)
Tony
  • 1,551
  • 20
  • 21
-1

What about one line solution?

Objective C

NSString *token = [[data.description componentsSeparatedByCharactersInSet:[[NSCharacterSet alphanumericCharacterSet]invertedSet]]componentsJoinedByString:@""];

Swift

let token = data.description.components(separatedBy: CharacterSet.alphanumerics.inverted).joined()
Nikolay Shubenkov
  • 3,133
  • 1
  • 29
  • 31
-2
-(NSString *)deviceTokenWithData:(NSData *)data
{
    NSString *deviceToken = [[data description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
    deviceToken = [deviceToken stringByReplacingOccurrencesOfString:@" " withString:@""];
    return deviceToken;
}
-2

Swift

    // make sure that we have token for the devie on the App
    func application(application: UIApplication
        , didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {

            var tokenStr = deviceToken.description
            tokenStr = tokenStr.stringByReplacingOccurrencesOfString("<", withString: "", options: [], range: nil)
            tokenStr = tokenStr.stringByReplacingOccurrencesOfString(">", withString: "", options: [], range: nil)
            tokenStr = tokenStr.stringByReplacingOccurrencesOfString(" ", withString: "", options: [], range: nil)



            print("my token is: \(tokenStr)")

    }
Vinod Joshi
  • 7,696
  • 1
  • 50
  • 51
-2

Use excellent category!

// .h file

@interface NSData (DeviceToken)

- (NSString *)stringDeviceToken;

@end    

// .m file

#import "NSData+DeviceToken.h"

@implementation NSData (DeviceToken)

- (NSString *)stringDeviceToken {
    const unsigned *deviceTokenBytes = [deviceToken bytes];
    NSString *deviceToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                     ntohl(deviceTokenBytes[0]), ntohl(deviceTokenBytes[1]), ntohl(deviceTokenBytes[2]),
                     ntohl(deviceTokenBytes[3]), ntohl(deviceTokenBytes[4]), ntohl(deviceTokenBytes[5]),
                     ntohl(deviceTokenBytes[6]), ntohl(deviceTokenBytes[7])];
    return deviceToken;
}

@end

// AppDelegate.m

#import "NSData+DeviceToken.h"

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    NSString *token = deviceToken.stringDeviceToken;
}

Works fine!

LLIAJLbHOu
  • 1,313
  • 12
  • 17
-3

Swift 3:

If any one is looking for a way to get device token in Swift 3. Use the below modified snippet.

    let characterSet: CharacterSet = CharacterSet( charactersIn: "<>" )

    let deviceTokenString: String = (deviceToken.description as NSString)
        .trimmingCharacters(in: characterSet as CharacterSet)
        .replacingOccurrences(of: " ", with: "")
        .uppercased()

    print(deviceTokenString)
  • 2
    I don't recommend using .description as that is not guaranteed to remain the same. See my answer here: http://stackoverflow.com/questions/9372815/how-can-i-convert-my-device-token-nsdata-into-an-nsstring/39754930#39754930 – swift taylor Sep 28 '16 at 19:44
-4
var token: String = ""
for i in 0..<deviceToken.count {
    token += String(format: "%02.2hhx", deviceToken[i] as CVarArg)
}

print(token)
Abdul Yasin
  • 3,480
  • 1
  • 28
  • 42
-4

The solution @kulss posted here, while lacking in elegance but having the virtue of simplicity no longer works in iOS 13, since description will work differently for NSData. You can still use debugDescription though.

NSString * deviceTokenString = [[[[deviceToken debugDescription]
                     stringByReplacingOccurrencesOfString: @"<" withString: @""] 
                    stringByReplacingOccurrencesOfString: @">" withString: @""] 
                   stringByReplacingOccurrencesOfString: @" " withString: @""];
johnyu
  • 2,152
  • 1
  • 15
  • 33
-7

Try this one unless the data is null-terminated.

NSString* newStr = [[NSString alloc] initWithData:newDeviceToken encoding:NSUTF8StringEncoding];

Naveed Ahmad
  • 3,176
  • 1
  • 15
  • 18
  • I tried that one, it doesn't work. I have it commented out in my code snippet. – Sheehan Alam Feb 21 '12 at 05:55
  • @SheehanAlam This guy made it through. Take a look how it's converting to string. http://stackoverflow.com/questions/4994302/didregisterforremotenotificationswithdevicetoken-doesnt-invoke-on-calling-regi – Naveed Ahmad Feb 21 '12 at 05:58
-9
NSString *tokenstring = [[NSString alloc] initWithData:token encoding:NSUTF8StringEncoding];
jrturton
  • 118,105
  • 32
  • 252
  • 268
Ravikant
  • 97
  • 4
  • 15