6

I am creating an iOS version of an existing Android app. On the Android side, hashCode() of a String (username) is sent to the server and based on that hash, a JSON object is returned.

On Swift, I tried hash and hashValue properties but both of them produces values that are different from their Android counterpart.

So I decided to write my own implementation based on Java's implementation:

int h = hash;
if (h == 0 && value.length > 0) {
  char val[] = value;
  for (int i = 0; i < value.length; i++) {
    h = 31 * h + val[i];
  }
  hash = h;
}
return h;

But when I write the above implementation in Swift, I get overflow crash. Can anybody help me here?

Thanks in advance.

Here is the Swift implementation:

I first had to write a Character extension that would return Ascii value of the character:

extension Character {
    var asciiValue: UInt32? {
        return String(self).unicodeScalars.filter{$0.isASCII}.first?.value
    }
}

Then I created a String extension with: 1. a property that returns Ascii values of each character in the String. 2. a hash method to return the hash (copying the Java code)

extension String {
    var asciiArray: [UInt32] {
        return unicodeScalars.filter{$0.isASCII}.map{$0.value}
    }
    func myHash() -> Int {
        var h = 0 as Int!
        for i in 0..<asciiArray.count {
            h = 31*h! + Int(array[i])
        }
        return h!
    }
}
10
  • And this is exactly why you shouldn't use a hash value to identify objects on a multi-platform system. Why not just use the username directly, or some other primary key? Commented Mar 8, 2017 at 17:34
  • 3
    Swift has overflow operators &+, &*, etc. exactly for this purpose. Commented Mar 8, 2017 at 17:36
  • I am editing my post to include the Swift implementation Commented Mar 8, 2017 at 17:36
  • Here is an example to implement Hashable in Swift 3 Commented Mar 8, 2017 at 17:44
  • 1
    What's the purpose of using the hash value? my opinion is the same as @Alexander one. Commented Mar 8, 2017 at 17:51

2 Answers 2

11

As the post is still missing an answer, here is the working code:

1) Write an extension for Characters, to map their ascii representation to an int - we need UInt32, as Java uses for the hashing a 32 bit system, not 64 bit.

2) Make sure our represented string does ONLY contain characters, which are mappable to ASCII

3) Now perform the mentioned hashing function

int h = 0;
if (h == 0 && value.length > 0) {
  char val[] = value;
  for (int i = 0; i < value.length; i++) {
    h = 31 * h + val[i];
  }
  hash = h;
}
return h;

So, we will get the following code snippet, which could be used in your projects.

// 1) Here is our Character extension
extension Character {
    var asciiValue: UInt32? {
        return String(self).unicodeScalars.filter{$0.isASCII}.first?.value
    }
}

extension String {
    // 2) ascii array to map our string
    var asciiArray: [UInt32] {
        return unicodeScalars.filter{$0.isASCII}.map{$0.value}
    }

    // this is our hashCode function, which produces equal output to the Java or Android hash function
    func hashCode() -> Int32 {
        var h : Int32 = 0
        for i in self.asciiArray {
            h = 31 &* h &+ Int32(i) // Be aware of overflow operators, 
        }
        return h
    }
}
Sign up to request clarification or add additional context in comments.

Comments

2

By default, swift throws an exception on integer overflow (unlike C or the standard Java integer operations). In order to preclude throwing the exception you have to use the special functions provided for that, like 'addWithOverflow'.

Alternatively you can build using the
-Ounchecked flag

3 Comments

The -Ounchecked flag disables many more checks than just overflow checks (for example, Array out of bounds, etc.).
@SaagarJha yes, I agree that it's not advisable. And while we are on the subject of ill advised, trying to duplicate the native string hash is probably only going to end in tears as well
It appears that they're trying to have a consistent hash value between iOS and Android.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.