xcode NSArrayM insertObject:atIndex:]: object cannot be nil - iphone

I'm new to Xcode. what i want is read plist data locally in my program. i got
NSArrayM insertObject:atIndex:]: object cannot be nil error. Here is what i declared and my plist file. Thanks
NSMutableArray *phoneArray;
NSString *path=[[NSBundle mainBundle] pathForResource:#"PhoneList" ofType:#"plist"];
phoneArray= [[NSMutableArray alloc]initWithContentsOfFile:path];
key type
Item 0 Dictionary
Item 1 Dictionary
Items have description, name keys as type of String.

Verify your plist, there is most likely a bad value. Items in an NSArray or NSDictionary can not be null. You can use Xcode to open the plist file to verify it.
Personally I use "PlistEdit Pro", it can provide somewhat better diagnostics when the plist is invalid. There is a Free Trial here of PlistEdit Pro.

- (void)insertObject:(id)anObject atIndex:(NSUInteger)index
The object to add to the array's content. This value must not be nil.
before any input from the plist file, please check to see that the element is not nil, to avoid the excetion

Related

writeToFile is overwriting the previous data

I'm using writeToFile property of NSDictionary in my code i'm trying to update a dictionary to documents directory like below,
NSDictionary *revisionDict = [NSDictionary dictionaryWithObject:currentItem.rev forKey:destPath];
NSArray *documentDirPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentDirPath objectAtIndex:0];
NSString *dictPath = [documentsDir stringByAppendingPathComponent:#"Revision.dictionary"];
[revisionDict writeToFile:dictPath atomically:YES];
here the problem is my dictionary rather than getting updated by new entries on each iteration it is getting overwitten by new entry.
How can i update my dictionary is there any alternate for writeToFile, Any help is appreciated in advance.
A dictionary in memory can be mutable; a dictionary written to disk is a snapshot of a complete set of information.
You won't get a "merge updates" behavior out of any of the framework methods like this. If you have an existing version that you want to add to or otherwise update, you'll need to load/have the original version in memory as a mutable dictionary, then make the changes or additions to it, and then save the whole new thing (with -writeToFile: or something else).
If you're adding a bunch of entries in a loop, add all the entries first, then write the dictionary to disk as a file when it's done.
Yes writeToFile will overwrite the previous content,
So you can just read the previous content of your file into NSMutableDictionary and then add new content to this mutableDictionary ,and then write this mutableDictionary(which holds both old and new content) to your file path.

How To remove a key value from Plist in ios?

I wanted to delete the key value in the Plist. I found answers like to delete the value assigned to it and another is to load a new plist but i need to delete a key value
(assuming this is programming-related)
You can load it into an NSDictionary, remove the key/value pair, then write it back:
NSString *pathToPlist = #"/Users/H2CO3/my.plist";
NSMutableDictionary *plist = [NSMutableDictionary dictionaryWithCOntentsOfFile:pathToPlist];
[plist removeObjectForKey:#"MyKeyIWannaDelete"];
[plist writeToFile:pathToPlist atomically:YES];
As of now this is not possible via coding. If you have these kind of scenario's, go with the database. So that, you can delete, what ever the row you want?
PlistDict is the Dictionary that is loaded in to the plist .By using following code we can remove the key value from the plist.
[plistDict removeObjectForKey:#"Key"];
Dictionary must be a Mutable one(NSMutableDictionary).

NSPredicate problem

I'm attempting to search an array of objects using NSPredicate. The objects have a number of NSString properties that I want to filter.
I have the following code to do the filtering:
NSString *predicateString = [NSString stringWithFormat:#"name like[c] %#",self.textFieldOutlet.text];
NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:predicateString];
NSArray *results = [[MySingleton sharedMySingleton].cardArray filteredArrayUsingPredicate:searchPredicate];
But I get the following error:
WebKit discarded an uncaught exception in the webView:shouldInsertText:replacingDOMRange:givenAction: delegate: <NSUnknownKeyException> [<CardObject 0x14a530> valueForUndefinedKey:]: this class is not key value coding-compliant for the key test.
If I put single quotes around the %# it works but only if the entered text is exactly the same as the value held for the name key and not if it is 'like' the value. Thus not very useful. I must be doing something wrong with the predicate string, can anyone advise?
Thanks in advance!
Apparently the error states that your object is not key-value compliant.
Try using NSDictionary instead
The error states that your CardObjects don't support the property 'test' with KVO.
However, your predicate simply asks to compare the name property so it looks like this predicate isn't the reason that your webview is crashing.
Can you add the contents of your webView:shouldInsertText:replacingDOMRange:givenAction: method to the question because that's where the bug is occurring.
I think that changing the predicate is changing the flow of the code later in this method, and that's where the error is (but without seeing the rest of your code, that's a bit of a guess!).
Ok I still have no idea why I get a webview error for the NSPredicate. But I have fixed the issue using the following predicate string:
(name like[cd] '*%#*')

NSArray to plist to TableView

Thanks in advance. I create an array with 6 parts, each an NSString in one of my views. Each string is taken from a UITextField. I want to make a save button that saves the Array into a plist. I then want a TableView to display a table sorted by the first object in the array, the first string.
I've created a blank plist with the name I want and named the plist the same thing as the array. Frankly, I'm lost after that. I don't understand if what I'm making is a dictionary in the plist or an array, and how to do it.
Once the table is made, I think I can handle pushing new views from the selected row.
Anything would help. Thanks and stack overflow has been really helpful.
Thanks again.
If you are really set on using files, to this to write an array to your .plist:
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:theArray forKey:yourKey];
[dictionary writeToFile:#"/somepath/blah.plist" atomically:YES];
[dictionary release];
This will set the root of your .plist file to be a NSDictionary.
If you want it to be an NSMutableArray just change the class of the *dictionary.
Answer via: primary source
To store data it's better to use NSUserDefaults and not files because reading and writing it it's much easier.
There is a primer at: Primer link

How do I store a string as an array in a Cocoa property list?

I am trying to save two strings. One string needs to be saved as type ARRAY in the pList and the second string needs to be saved as String in the Array.
I can use the code:
[dictionary setObject:(id)anObject forKey:(id)aKey>]
but it doesn't save it correctly. I can cast one of the strings as an array, but it still doesn't work right.
What is the proper method for saving an array to the pList?
Here is what my pList looks like:
<dict>
<key>Test One</key>
<array>
<string>A13#</string>
</array>
<key>Another Test</key>
<array>
<string>1111111111</string>
</array>
<key>Test Three</key>
<array>
<string>2222222222</string>
</array>
<key>Final Test</key>
<array>
<string>3333333333</string>
</array>
</dict>
here is the method I am using to try to
-(void)writeToFile:(NSString *)s1{
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:#"saved" ofType:#"plist"];
NSMutableDictionary *dictionary = [[[NSDictionary alloc] initWithContentsOfFile:plistPath] mutableCopy];
NSString *tempString = [NSString stringWithFormat:#"1234567"];
[dictionary setObject:tempString forKey:s1];
[dictionary writeToFile:plistPath atomically:YES];
}
You can't cast or otherwise convert a string into an array; they're separate, distinct objects. It's the same as if in real life you try to turn your dog into a station wagon, it isn't happening.
Instead, put your dog inside the station wagon (or put your string(s) inside an array). You can create the array with [NSArray arrayWithObjects:#"string1", #"string2", nil];. Stick that inside your dictionary for a given key, along with your final string for another key, save it, and you'll have a plist with an array of one or more strings.
Also, in your code example your dictionary is leaking memory. Read up on memory management in Objective-C, you're going to run into lots of crashes and performance issues until you understand it well.
You an convert a string to a single element array with
[NSArray arrayWithObject:str];
So if you want your plist to contain entries as arrays of strings, and you want just a single string as an element, then you do something like:
[dictionary setObject:[NSArray arrayWithObject:tempString] forKey:s1];
I don't actually no why you would want it this way unless you want to allow for multiple strings per key at some other time.
Also, as Marc mentioned, you are leaking the initial (unmutable) dectionary you create. Read the memory management rules at http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html.
Further, you should never write inside your application's bundle. For one thing, your application may be on a write protected volume or the current user may not have permissions to change it. For another, the file would then be shared by all users. And for a third, it would break the code signing. Instead, write the file to either the Preferences folder or the Application Support folder.
And finally, if these are intended to be user preferences of some sort, then you should use the preferences system, which allows configuring defaults and stores the preferences in the preferences folder for you. See http://developer.apple.com/documentation/Cocoa/Conceptual/UserDefaults/UserDefaults.html for more information.
The correct way to save an NSArray (by itself) to a plist file is as follows:
NSArray* anArray = ...;
[anArray writeToFile:#"/path/to/file.plist" atomically:YES];
However, you can't save an NSString as an array. Given the XML plist you provided, if you want to add entries with the same format, you can use this much simpler code:
- (void) writeToFile:(NSString *)string {
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"saved" ofType:#"plist"];
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];
[dictionary setObject:[NSArray arrayWithObject:#"1234567"] forKey:string];
[dictionary writeToFile:plistPath atomically:YES];
}
This also avoids a memory leak in your code, where the receiver of -mutableCopy escapes with a retain count of 1. (This isn't a problem under GC, but it's still bad practice.) You shouldn't need to use +[NSString stringWithFormat:], just use a string literal. If you want to use a different as the string in the array, you can either pass it in as an additional parameter, grab it from another method, etc.
This method is still brittle in that it only stores one string in the array matched with the given key — also, the method name would be better if it were more indicative of exactly what it does. Also, if there will only ever be one string value for each key, you might consider revising the plist to omit the arrays entirely, since it just chews up space and complicates the code.