I am creating an iOS word game and need to import every word in the English dictionary. I have to check if a string is part of the array or set or whatever it may be. What is the best and most memory efficient way of importing and utilizing the data?
I feel like I'm working for them, haha, but LexiconText has a very nice product indeed, and it isn't too hard to determine if the word is in the dictionary or not:
Lexicontext *dictionary = [Lexicontext sharedDictionary];
BOOL wordExists = [dictionary containsDefinitionFor:#"MyWord"];
Note: I am not affiliated with lexicontext in any way, other than being a happy customer.
You should use sqlite or another database to store the dictionary. Then you don't have to load it all into memory, but get fast loading of words.
Related
I've been using c style enumeration in objective C when I need to know at which index the object is. However, apple recommends a different style.
So, they recommend that:
for(int i=0;i<array.count;i++)
NSLog(#"Object at index %i is: %#", i, array[i]);
be changed to
int index = 0;
for (id eachObject in array) {
NSLog(#"Object at index %i is: %#", index, eachObject);
index++;
}
Is there a good reason for this other than stylistic preference?
And a follow up: How would one enumerate the letters in a String using the second kind of enumeration?
A while back someone analyzed the different enumeration options for an NSArray. The results are very interesting. It's worth noting that the tests were done on iOS4 and OSX 10.6 though.
http://darkdust.net/writings/objective-c/nsarray-enumeration-performance
In general, he shows that when dealing with something other than very small arrays, fast enumeration is better performing than block enumeration, and both are better performing than basic enumeration (array[i]).
It would be great to see these tests on iOS7!
Fast enumeration, the second option, can be better optimized by the compiler. So besides resulting in cleaner looking code that doesn't have to track the index, you also end up with faster code. So any time the second option would work, it likely should be used.
Now if you wanted to iterate over the characters in an NSString, you couldn't by default do that using fast enumeration. The only way you could do it is if you first put the characters into an NSArray, most likely using a standard for loop to iterate over the characters and add them manually. But this would defeat the purpose of using fast iteration in the first place since you have to do a standard for loop first anyway. You would only do this if you wanted to do fast iteration over this same string of text many many times, and could add them to an array first just once.
The advantage is simply that it's faster to write and easier to read. It's especially useful when you don't need the index (i for example) other than for accessing the object.
I do not understand how this makes sense. I put two objects in the discoveryinfo dictionary inside the MCNearbyServiceAdvertiser object that I create and the browser doesn't see the advertiser, yet when I move the second object out of the dictionary and comment it out at the end of the line, the browser sees the advertiser. Does the discoveryinfo dictionary only accept one object to work? I have a string as the first object and an array as the second. Here is what it looks like:
advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:myPeerID discoveryInfo:#{#"Name": [[NSString alloc] initWithString:myUniqueID], #"Peers": [[NSArray alloc] initWithArray:connectedPeersAry]} serviceType:#"Blahblah"];
And before that line, I tried this simpler format (but went to the above just in case the syntax was the problem):
advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:myPeerID discoveryInfo:#{#"Name": myUniqueID, #"Peers": connectedPeersAry} serviceType:#"FRCSCOUT"];
I guess I can put a dictionary or array inside the discoveryinfo dictionary, but I feel it's a pretty dumb way of doing things because a dictionary shouldn't ever be limited to one object for any case.
I'll go ahead and put my objects in another layer to "conserve space" inside the discoveryinfo dictionary, but if any of you find a better way of doing things or if you are seeing the same problem, please let me know.
You can have multiple objects in the discoveryInfo dictionary, but keep in mind that the dictionary will be encoded in a Bonjour TXT record. This imposes a few restrictions on what can be put into that dictionary.
As stated in the documentation for [MCNearbyServiceAdvertiser initWithPeer:discoveryInfo:serviceType:]:
This data is advertised using a Bonjour TXT record, encoded according to RFC 6763 (section 6). As a result:
The key-value pair must be no longer than 255 bytes (total) when encoded in UTF-8 format with an equals sign (=) between the key and the value.
Keys cannot contain an equals sign.
For optimal performance, the total size of the keys and values in this dictionary should be no more than about 400 bytes so that the entire advertisement can fit within a single Bluetooth data packet.
Well, found my problem. As quoted by Apple in their class reference for MCNearbyServiceAdvertiser:
"The content of discoveryInfo will be advertised within Bonjour TXT records, so you should keep the dictionary small for better discovery performance."
So, looks like I'll have to use a comma separated string of some sort...
EDIT
I misunderstood the Multipeer Connectivity API. I thought the roles were reversed and the Advertiser was basically the public host for a Multipeer Session, but it should be the Browser that invites Advertisers. I now just have the Unique ID generated as the discovery info.
Thank you all for your help and sorry for the API confusion on my part.
I am sorry to ask this but I have searched for hours on doing this but I really don't understand it. Please help me. I have a .plist file in my Xcode project and it's root is a Dictionary type. It contains about 50 more dictionaries. Inside the dictionary contains strings. (Dictionary(root) > Dictionary > String. I added a search field to my toolbar and linked it to my code. I am able to get what the user types but then how do I "search" after getting what the user typed? Is there a method for this and how do I link it into my .plist? Thank you so much!!!
You want to search for the user entered string in your Dictionary of Dictionaries?
You're going to have to iterate each dictionary, asking [dict objectForKey:userEntry] in each. Not sure if you want to only find first match or all matches too.
Additionally, you may want to create an abstraction of your Dictionary of Dictionaries to reduce the scale of the problem and clarify the API. In simpler terms, wrap your Dictionary of Dictionaries in a class and put a sensible (non-dictionary-based) set of methods on it. It's probably worth the effort.
To load the plist into a Dictionary, look at [Dictionary dictionaryWithContentsOfFile].
Edit: Filtering options on NSDictionary
Have you looked at the following options for filtering values in an NSDictionary:
[NSDictionary keysOfEntriesPassingTest:] (10.6 and later) or
take the [rootDictionary allValues] NSArray and use Predicates, perhaps like this.
I've been developing iOs and OsX applications for several months now and it still feels like I'm doing something wrong. I try to stick to the Guidelines and I try to use the objects Apple provides as often as I can. But it seems they are making my code very hard to understand.
Example:
When I want to just "increment" a NSNumber Object (which is not mutable, but you get what I mean), I use awkward lines like this:
int value = [counter intValue];
counter = [NSNumber numberWithInt:value +1];
Is this really necessary? Are there more elegant ways (i++, inc(i), etc) to do simple things like this? Especially when you're working with coordinates it gets really frustrating and hard to work with.
When working with Objective C I feel like I'm allocating, deallocating and converting objects all the time and wasting so much of my own time and the CPU time with all those conversions. Thanks for your time, I really appreciate your answers and I'm looking forward to your tipps!
Using your example, is there any particular reason you are using NSNumber for a counter? It would be much better to use int so that you can use value++.
The key to good Objective-C code is to use objects when they make sense. Don't be afraid to use non-object data types and don't be afraid to drop down (not the best term) to C when required.
As #sosborn wrote: use objects only when it's required. But: when it's required, and you still feel wrong, simply don't. Write a macro for incrementing an NSNumber, use ARC for let the compiler do the memory management for you as efficiently as possible, etc. If you really worried about time, use C or assembly for time-critical tasks, or C++ if you want OO.
P. s.: NSNumber increment macro:
#define NSNUM_INC(n) do { n = [NSNumber numberWithInt:[n intValue] + 1]; } while (0);
You can write your category for NSNumber to implement the methods you need. For your example the file of category contains the following function:
-(NSNumber *)numberByAddingInt:(int)i
{
...
}
Include this file and then you can call it as:
counter = [counter numberByAddingInt:1];
Instead of implementing my own I was wondering if anyone knows of a histogram or bag datastructure implementation in Objective-C that I can use.
Essentially a histogram is a hashmap of lists where the lists contain values that relate to their hash entry. A good example is a histogram of supermarket items where you place each group of items dairy, meat, canned goods in their own bag. You can then very easily access each group of items according to their type.
NSCountedSet is a multiset (aka "bag") that counts distinct objects, but doesn't allow duplicates. However, based on your explanation, I don't think that's what you need, and neither is a histogram, which automatically buckets values based on a set of (usually numerical) ranges.
I believe what you really want is a multimap, which is a "key to one-or-more values" relation. The data structures framework I maintain includes CHMultiDictionary, a multimap implementation. I won't claim by any means that it's perfect or complete, but I hope it may be helpful for your problem.
It sounds to me like you simply want a dictionary of arrays. You can put NSArrays as elements of NSDictionarys, something like:
NSMutableDictionary* dict = [NSMutableDictionary dictionary];
[dict setObject:[NSMutableArray arrayWithObjects:#"milk", #"eggs", #"cheese", nil] forKey:#"dairy"];
[dict setObject:[NSMutableArray arrayWithObjects:#"steak", #"sausages", #"mince", nil] forKey:#"meat"];
[[dict objectForKey:#"meat"] addObject:#"lamb"];
NSLog( #"Dictionary is %#", dict );
There's one in the GNU Objective-C Class library, but the docs appear to be pretty incomplete and the project's homepage must be currently having a problem -- still, if GPL software is acceptable for your project, you might want to download and check the sources.
CFIOMultimap apparently is an implementation of a multimap. However, as of the time of writing I couldn't get it to work. It returns nils all the time when I subscript.
Perhaps it can be fixed and adapted for your use.