Objective C equivalent of intern() in java
I got to implement some synchronization algorithms depending on strings. I mean two threads have to be synchronized and the pair of threads both depend on a string value (one pair of threads for String A, one pair for String B, and so on).
In java, I could implement the algorithm using the method intern to get a single lock object that is shared by both threads. Java pulls all litteral in a jvm built-in pool and interne allows to transform any string created dynamically into a litteral in the pool.
I understood that there is also a pooling mechanism in Objective C.
But is there any equivalent to intern() in Java, i.e a way to transform a normal String into a litteral String from the pool of String constants. To get the reference to this unique String litteral so that both my threads could get synchronize on the same object.
I know there are some work around but they all imply a lot of String comparisons that I would like to avoid. (Although I believe intern does it but in an optimized way...)
To explain my problem in more general term : I want to avoid having a Dictionnary that maps a String to a 开发者_开发问答lock. Java allows me to do that thanks to intern as the String litteral (pooled) will become the lock. Is there any equivalent or must I use this map.
Thanks folks, Stéphane
I program regularly in both Java and Objective-C.
First, what you describe seems a less-than-ideal way to share a lock. It's tricky, it's brittle, and it will confuse other coders not so intimate with how String interning works. Why not just have a lock object in one class exposed to the other as a constant?
public class Foobar {
public static final Object LOCK = new Object();
public void doLockedStuff() {
synchronized (LOCK) {
// code here
}
}
}
public class Barfoo {
public void doLockedStuff() {
synchronized (Foobar.LOCK) {
// code here
}
}
}
And then you can adopt a similar approach in Objective-C - a class method exposing a shared LOCK object.
I think mapping the strings to the locks they represent is your best bet.
You don't want to lock on the String itself (or an interned version) because it's a shared object in the JVM. You don't know if another component in the JVM is doing the same thing, which could cause a deadlock.
Java Concurrency in Practice describes this better, but I can't find a reference at the moment.
The map containing your locks won't incur a large performance problem if you use a HashMap because Strings are immutable and the hash code of the String will likely only have to be calculated once.
I finally used a dictionnary that binds every string to a conditionnal lock.
Thanks all
Without suggesting that is the best way to generate the locks that you are looking for but here is a little hack to give you the effect you want:
NSString *stringA = [NSString stringWithString:@"Hello"];
NSString *stringB = [NSString stringWithFormat:@"%@l%@",@"Hel",@"o"];
NSString *stringC = [NSString stringWithFormat:@"Hell%@", @"o"];
NSLog(@"%p / %p / %p", stringA, stringB, stringC);
NSNumber *lockA = [NSNumber numberWithUnsignedInteger:stringA.hash];
NSNumber *lockB = [NSNumber numberWithUnsignedInteger:stringB.hash];
NSNumber *lockC = [NSNumber numberWithUnsignedInteger:stringC.hash];
NSLog(@"%p / %p / %p", lockA, lockB, lockC);
You will notice that eventhough the strings have different addresses, their corresponding NSNumbers don't. That's because NSNumbers for a given number is a singleton.
You can now use @synchronize()
on these "lock" objects.
-- Edit --
The fact that NSNumbers are singletons for a given value is an internal detail to the implementation, which is one reason why it might be a good idea to shop around for a real locking mechanism such as a dictionary indexed by NSString for example.
精彩评论