Iphone - NSString hash using [myString hash] gives me negative value - iphone-sdk-3.0

I am generating a hash from a NSString, using [myString hash] and the result I get is a negative value.
The Apple's documentation is saying :
(NSUInteger)hash
Return Value An unsigned integer that
can be used as
Any idea ?
** Edited **
Try this code in your device :
NSString *udidStr = [[UIDevice currentDevice] uniqueIdentifier];
NSUInteger udid = [udidStr hash];
For some device I get a negative value.
Thanks

That is probably just a display problem. I bet you are assigning it to a signed integer, or the debugger assumes (as most do) that all integers are signed, since that is more common.
Any number with the first bit set will be "negative", but that doesn't mean the value is incorrect.

Related

is NSDictionary non-ordered completely

As we know,NSDictionary is non-ordered.however,when keys is number,when the dictionary is printed,they are printed by ascending number. i have try many times.
the order of a dictionary depends on the value that is returned by the hash method of the added key-object. it is very like, that NSNumber returns its value, it is was created with an Integer. in that case your observation would be correct.
more infos: http://bynomial.com/blog/?p=73
try ing this code
NSArray *numbers = #[#0,#1,#2,#3];
for (NSNumber *n in numbers) {
NSLog(#"%ld:%#", (unsigned long)[n hash], n);
}
it produces this output
0:0
2654435761:1
5308871522:2
7963307283:3
seems as if Knuth's hash algorithm was implemented half.
The original is
hash(i)=i*2654435761 mod 2^32
here it seems to be just
hash(i)=i*2654435761

Why is ([str length] - 2) larger than 0 when str is nil?

When the follow code is run it goes inside the for loop and run NSLog. Why does this happen?
NSString *aString = nil;
for (int i=0; i<([aString length]-2); i++) {
NSLog(#"Inside loop.");
}
As i figure [aString length]-2 results in -2 and that's less then 0?
To be more precise, -[NSString length] returns an unsigned integer, so subtracting two from zero (remember, calling any method on nil gives you zero) doesn't give you -2, it gives you a very, very large number. Cast it to an int (or an NSInteger) to get the results you want.
You're asking the for loop to run if i<-2; as [NSString length] returns an unsigned integer, this value will wrap round to max int - 2.
You're passing a message to a nil object there too: [aString length]. I'm not sure this is defined behaviour, and may return a strange range of values, though I suspect it may be clever enough to return 0. My commentators say that this suspicion is true.

Multi-character character sequence in 3rd party library

I'm using a 3rd party library for an iOS project I work on, and I'm down to one warning left in the project, namely on this line of code
[NSNumber numberWithUnsignedLongLong:'oaut']
And the warning is
Multi-character character constant
I suck at C, so I don't know how to fix this, but I'm sure the fix is relatively easy. Help?
EDIT: More context.
#implementation MPOAuthCredentialConcreteStore (KeychainAdditions)
- (void)addToKeychainUsingName:(NSString *)inName andValue:(NSString *)inValue {
NSString *serverName = [self.baseURL host];
NSString *securityDomain = [self.authenticationURL host];
// NSString *itemID = [NSString stringWithFormat:#"%#.oauth.%#", [[NSBundle mainBundle] bundleIdentifier], inName];
NSDictionary *searchDictionary = nil;
NSDictionary *keychainItemAttributeDictionary = [NSDictionary dictionaryWithObjectsAndKeys: (id)kSecClassInternetPassword, kSecClass,
securityDomain, kSecAttrSecurityDomain,
serverName, kSecAttrServer,
inName, kSecAttrAccount,
kSecAttrAuthenticationTypeDefault, kSecAttrAuthenticationType,
[NSNumber numberWithUnsignedLongLong:"oaut"], kSecAttrType,
[inValue dataUsingEncoding:NSUTF8StringEncoding], kSecValueData,
nil];
if ([self findValueFromKeychainUsingName:inName returningItem:&searchDictionary]) {
NSMutableDictionary *updateDictionary = [keychainItemAttributeDictionary mutableCopy];
[updateDictionary removeObjectForKey:(id)kSecClass];
SecItemUpdate((CFDictionaryRef)keychainItemAttributeDictionary, (CFDictionaryRef)updateDictionary);
[updateDictionary release];
} else {
OSStatus success = SecItemAdd( (CFDictionaryRef)keychainItemAttributeDictionary, NULL);
if (success == errSecNotAvailable) {
[NSException raise:#"Keychain Not Available" format:#"Keychain Access Not Currently Available"];
} else if (success == errSecDuplicateItem) {
[NSException raise:#"Keychain duplicate item exception" format:#"Item already exists for %#", keychainItemAttributeDictionary];
}
}
}
EDIT 2: They were attempting to meet the requirements of this by creating that NSNumber:
#constant kSecAttrType Specifies a dictionary key whose value is the item's
type attribute. You use this key to set or get a value of type
CFNumberRef that represents the item's type. This number is the
unsigned integer representation of a four-character code (e.g.,
'aTyp').
In C and Obj-C the single-quote ' is used only for single-character constants. You need to use the double-quote: "
Like so:
[NSNumber numberWithUnsignedLongLong:"oaut"]
That covers the warning, but there's also a semantic issue here. Although a single character constant, such as 'o', can be treated as an integer (and can be promoted to an unsigned long long), a "string" (char * or char []) cannot, which means you can't use "oaut" as an argument to numberWithUnsignedLongLong:
Update:
I guess the four-character code is supposed to be treated as an integer, i.e., the 8 bits of each char put in place as if they together were a 32-bit int:
char code[] = "oaut";
uint32_t code_as_int = code[0] | (code[1] << 8) | (code[2] << 16) | (code[3] << 24);
[NSNumber numberWithUnsignedLongLong:code_as_int]
although I'm not sure which endianness would be expected here, nor why this is calling for an unsigned long long, unless just to be certain there are enough bits.
Rudy's comment, now that I think of it, is correct -- multi-character constants are allowed by some compilers for exactly this purpose (it is "implementation-defined" behavior).
'oaut' (single quotes) is a character, so the compiler tries to interpret it as a multi-byte character but can't make any sense of it. That explains the error message.
I guess that if you gave a proper string, like #"oaut", you'd get another error message, since numberWithUnsignedLongLong: expects an unsigned long long, not a string or a character. Are you trying to pass a variable with the name "oaut"? If so, use
[NSNumber numberWithUnsignedLongLong: oaut];
If not, then please explain what "oaut" is.
Edit
'oaut' may actually be the original value. There are/were multi-character character constants in C. Using a (4 byte) char, used as int and promoted to unsigned long long would then be possible. This must be old code. It seems such code was accepted by CodeWarrior.
Assuming that really a multi-char char const was meant, 'oaut' looks like a "magic number" and this value was chosen because it is the beginning of "oauth". I guess it should either be value 0x6F617574 or 0x7475616F.
#Josh Caswell 's answer is partially right, the simplest and "official" solution is:
[NSNumber numberWithUnsignedInt:'oaut']
unsigned int's length is 32-bit in both 32-bit and 64-bit cpu, there's a practical example from Apple: https://developer.apple.com/library/ios/samplecode/CryptoExercise/Listings/Classes_SecKeyWrapper_m.html

Assign textView's value to int, IOS

I have a textView (tF1) that will be supplied with a numeric value by the user. I need to assign that to number to the int (n).
This is what I came up with:
#import "blabla.h"
int n;
....
[tF1 resignFirstResponder];
n = (int)[tF1 text];
NSLog(#"n is, %d",n);
My problem is that the int value comes out to be a vary large number, like 82296768, for a textview value of 4.
Any and all help would be greatly appreciated! :)
SOLVED
changed line,
n = (int)[tF1 text];
to,
n = [[tF1 text] initValue];
NSString has a method intValue that you should be using:
n = [[tF1 text] intValue];
From the documentation for NSString, the other numeric values you can retrieve are:
– doubleValue
– floatValue
– intValue
– integerValue
– longLongValue
– boolValue
To invert this process, that is to add a numeric value as a string, you can use the NSString method -stringWithFormat:, e.g.
[tF1 setText:[NSString stringWithFormat:#"%d", someIntValue]];
You should be using an NSNumberFormatter to get the numeric value. Take a look at the method numberFromString: in the documentation.

need help converting an MPMediaItemPropertyPersistentID to a string and back again

I'm getting the ID of a media item from the MPMediaPickerController. According to the documentation, this value is an NSNumber object containing a uint64_t (unsigned long long). I would like to convert it to an NSString for saving in my data model. However, when I convert it to a string its value changes, and when I convert it back to a number it changes again! Obviously I'm not understanding something about these data types. Can you help?
MPMediaItem *mediaPicked;
// set mediaPicked to an MPMedia item using MPMediaPickerController...
NSLog(#"id as number: %qu", [mediaPicked valueForProperty:MPMediaItemPropertyPersistentID]); // outputs 566042331449280
NSLog(#"id as string: %#", [[mediaPicked valueForProperty:MPMediaItemPropertyPersistentID] stringValue]); // outputs 16204893883745507648
NSLog(#"id as number: %qu", [[[mediaPicked valueForProperty:MPMediaItemPropertyPersistentID] stringValue] longLongValue]); // outputs 9223372036854775807
If I try to play the media item before this conversion, it always works. But if I try to play the media item after this conversion, only about half of the media items I've tried work. So some ID values survive the conversion and some don't.
You are starting by saying this:
NSLog(#"id as number: %qu", [mediaPicked valueForProperty:MPMediaItemPropertyPersistentID]); // outputs 566042331449280
But that's wrong. %qu means "this thing is an unsigned long long". But this thing is not an unsigned long long. It's an object! It's an NSNumber wrapped around an unsigned long long. You are lying to NSLog, so you're getting garbage output in your very first statement.
Now, try this on your own machine:
uint64_t x = 16204893883745507648ULL;
NSLog(#"%qu", x);
NSNumber* n = [NSNumber numberWithUnsignedLongLong:x];
NSLog(#"%#", n);
NSLog(#"%#", [n stringValue]);
All of those NSLog statements give the same result - because they are all correct formulations, unlike the one you started with. So, those NSLog statements show you the kind of thing you ought to be saying.
Now, you might think: Oh, great, so I can get from an NSNumber to an NSString with stringValue after all. Yes, but you can't get back again. We cannot get from [n stringValue] to a correct NSNumber by using longlongValue, because a long long is not an unsigned long long. There is no unsignedLonglongValue. So you can't get there from here.
So what's the right thing to do? Don't convert at all! You've got an NSNumber, it's valid, just keep it and use it. An NSNumber is a value you can store in your model. (For example, it can go into a dictionary as a value or as a key, it can be a value in user defaults, and so on.)