0

I want to store some data of NSMutableArray type to file. I tried the following code but it did not work for me:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"test"];
[self.arrayHit writeToFile:filePath atomically:YES]

One thing I am not sure of is, the path after stringByAppendingPathComponent, I just create an empty file within my project, the structure is like the following: enter image description here But after a while, I came across an answer in StackOverflow mentioned that the code above can not preserve NSMutableArray but instead works for NSArray, so I tried to use the suggested code below to preserve NSMutableArray:

BOOL success = [NSKeyedArchiver archiveRootObject:self.arrayHit toFile:@"test"];

but still no luck.

There are two things I am not sure: 1. What file should I create to store the data, since I don't know any, I just created an empty file (I see there are other choices like property list, string file, rich text file etc.) see image below: enter image description here 2. What path should I put to store the data? If the file is at the same directory of my code, can I just use @"test" directly?

2
  • What error are you getting? Commented Mar 31, 2014 at 17:34
  • @Flexicoder no error, I tried to print the return value of [self.arrayHit writeToFile:filePath atomically:YES] and [NSKeyedArchiver archiveRootObject:self.arrayHit toFile:@"test"], they are both 0, mean the preservation did not succeed. Commented Mar 31, 2014 at 17:43

3 Answers 3

2

To explain what is going on with the code you are using

Your first bit of code:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"test"];

[self.arrayHit writeToFile:filePath atomically:YES]

Will write a file to your user Documents folder. Because that is what is asked for by NSDocumentDirectory AND in the Users domain by NSUserDomainMask

Your second bit of code:

 BOOL success = [NSKeyedArchiver archiveRootObject:self.arrayHit toFile:@"test_me"];

When run from Xcode will write to

~/Library/Developer/Xcode/DerivedData/myApp-cgammojtjqvbdcappvddborkhkpk/Build/Products/Debug/test

Not what you want. But when the App runs from else where you will not get a file at all.

This is because you have not specified a valid path like you did in your first code.

So it should be for example and using the Users Applications Support directory this time

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"test"];

  BOOL success = [NSKeyedArchiver archiveRootObject:self.arrayHit toFile:filePath];
      NSLog(@"success %hhd",success)

But I really suggest you read the basics and other documentation to gain a better understanding of what you are writing

I just found Start Developing Mac Apps Today Posted some time in 2013 which looks like Apple new way of giving people a head start in learning. Looks like a good place to start

It includes

Read This Article Now: Acquire Foundational Programming Skills describes the basic tasks in Objective-C programming. The concepts explained in this article are essentially the same for Mac and iOS development.

Which is what we are using here.

But I suggest you start from the beginning..

Sign up to request clarification or add additional context in comments.

1 Comment

thank you for your reply, but I tried the code you provided but still got 0 when print success.
1

You don't give details of exactly what errors you received so the following is fairly general in the hope it helps.

You don't create a file in your Xcode project to store your data, your application should create its own file at runtime.

Files created by your application which are not directly saved in a location selected by your user should be stored in the applications "Application Support" folder. This is a folder named after your application - its name or bundle ID - stored within "Application Support" with "Library". You use the API as you have to location "Application Support" and then create your applications own subfolder if needed (i.e. if a previous run hasn't created it).

NSKeyedArchiver is a good option to store your data as it can represent more types than using a property list (plist) - which is what writeToFile: produces. For NSKeyedArchiver to work every object in your dictionary must support the NSCoding protocol. Many framework types support this protocol, if your dictionary contains instances of your own classes you need to support NSCoding in your own classes, read the documentation for how to do this.

HTH

4 Comments

hi, thank you for your reply. I deleted the file and tried the following code BOOL success = [NSKeyedArchiver archiveRootObject:self.arrayHit toFile:@"test.txt"]; and print success, it is always 0. anything wrong here?
@photosynthesis - you are supplying a file name not a path name, where do you think the file will be located? Supply a path name to a file in your application's "Application Support" folder as explained above.
if I want the file to be located at the same folder with other .h and .m files, that is the file should stay together with my project not in a fixed location of my computer (the picture above tells the structure I wanna have), what path should I provide to it?
The .h & .m files are in your project source folder, and that folder has no connection to your running application (and certainly not to your users running application as they don't have your source folder!). While you can store files for reading within your application bundle you cannot write files into your application bundle. Put the file in your applications "Application Support" folder. If you want to "prime" the file you can store a copy in your application bundle and load from there if the file is not present in the "Application Support" folder.
1

The file doesn't need to exist ahead of time. What is important is that the classes of the objects in the array support the NSCoding (or NSSecureCoding) protocol. This will allow them to be serialized and written to disk using NSKeyedArchiver and read from disk and deserialized back into objects using NSKeyedUnarchiver.

If you are using custom objects, you need to implement the NSCoding methods yourself. Otherwise, check the class reference for the class you are trying to serialize and ensure that it already adopts NSCoding. Many Foundation Framework classes support NSCoding out of the box (NSString, NSURL, NSArray, NSDictionary etc.).

In your case, NSMutableArray already supports NSCoding so you need to make sure the class of the objects inside the mutable array also implement the required NSCoding methods.

1 Comment

thank you for your reply. the objects in NSMutableArray are simply NSNumber type, so I believe they are NSCoding supported. I deleted the file and tried the following code BOOL success = [NSKeyedArchiver archiveRootObject:self.arrayHit toFile:@"test.txt"]; and print success, it is always 0. anything wrong here?

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.