Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.
So, I have managed to save the default data for each element I save into a dictionary. My problem now is how to create the plist and write to it. I assuem I shall create it in the same directory as the images self and that path do I have. I have been seaching for the syntax for creating a plist in the code, but I did not find anything helpful... do you have any suggestions?
Thanks in advance!
MACloop

If you save a NSDictionary or NSArray (which you use depends on what you are doing, I would have thought an NSArray containing NSDictionaries would be correct) to a file you get a plist. Use the well documented writeToFile:atomically: method.
 
So, I have managed to save the default data for each element I save into a dictionary. My problem now is how to create the plist and write to it. I assuem I shall create it in the same directory as the images self and that path do I have. I have been seaching for the syntax for creating a plist in the code, but I did not find anything helpful... do you have any suggestions?
Thanks in advance!
MACloop

How do I detect the size of an directory that I have created in the sandbox?
 
If you save a NSDictionary or NSArray (which you use depends on what you are doing, I would have thought an NSArray containing NSDictionaries would be correct) to a file you get a plist. Use the well documented writeToFile:atomically: method.

Thanks alot! Ok, I think I have to read some more about adding this nested structure (dictionaries in arrays) to the list. I have read about the method you mentioned and I am sure this is the right one to use.
MACloop
 
Look, it's time you used the documentation instead of asking for every little thing to be spoon-fed to you.

I read the documentation all the time and do not want you to spoon-feed me. But the documentation is huge and sometimes it is quite hard to find whqt you are looking for. But I don not give up ;)
 
I read the documentation all the time and do not want you to spoon-feed me. But the documentation is huge and sometimes it is quite hard to find whqt you are looking for. But I don not give up ;)

Well a quick hint would be "directory size Cocoa" in Google.
 
Look, it's time you used the documentation instead of asking for every little thing to be spoon-fed to you.

Ok, I have spend some thime reading this and one question is still unanswered: Do I have to create the plist in the dir where in my case the pictures are saved/cached?
I check in my code if there is a plist available:
Code:
if ([[NSFileManager defaultManager] fileExistsAtPath:plist_filePath] == NO)

If it is not available, I go on and create this file:
Code:
NSArray *rootArray = [NSArray arrayWithObject:imgDict];
BOOL success = [fileManager createFileAtPath:plist_filePath contents:rootArray attributes:nil];

In this code I get a warning about sending in the array into the file as content.

Is this the wrong way of doing it? I do not see any examples on how to actually create the plist file it self in the documentation... Any Advice?
MACloop
 
I suggest you read more carefully in future. I already told you how to do this in this thread. Take a look further back for the writeToFile:atomically: method.
 
OK, i will do that. Thanks again!
MACloop

So I have followed this sample code from apple and have done as I think nearly exactly the same. The difference is - I do not get anything saved into my plist... NSDictionary is parent class to NSMutableDictionary, or am I wrong? I do not really understand what I have done/implemented wrong here?

Code:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *newDirPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/imageCahce"];
NSURL *u = [NSURL URLWithString:[urls objectAtIndex:i]];
NSString *fileName = [[u path] lastPathComponent];
NSString *filePath = [newDirPath stringByAppendingPathComponent:fileName];
		
if([[NSFileManager defaultManager] fileExistsAtPath:filePath] == NO){//no img excists
    BOOL success = [fileManager createFileAtPath:filePath contents:d attributes:nil];//create img file
    if(success == YES){
        NSLog(@"File was created successfully at %@",filePath);
    }
    else {
        NSLog(@"Failed to create file at %@",filePath);
    }
    NSString *plist_filePath = [[NSBundle mainBundle] pathForResource:@"ImgCache" ofType:@"plist"];//path to plist
    if (plist_filePath) {//if path excists
        NSArray *array = [[NSArray alloc] initWithContentsOfFile:plist_filePath];//saving content from plist into array
        NSMutableArray *cacheArray = [[NSMutableArray alloc] init];
        for (NSString *element in array) {//every element in the plist array is set into the cache array
            [cacheArray addObject:element];
        }
        [array release];
				
        NSDictionary *imgDict = [NSDictionary dictionaryWithObject:fileName forKey:@"Name"];//new dict with the fileName and key=Name
        [cacheArray addObject:imgDict];//add object to cacheArray
        [cacheArray writeToFile:plist_filePath atomically:YES];//write cacheArray to file
        [cacheArray removeAllObjects];
        [cacheArray release];
    }
}
 
Do not, under any circumstances, ever write to a path within

Code:
[NSBundle mainBundle

Go and read the iPhone OS Programming Guide as I suggested earlier in this thread to find out where you can/should write to.
 
Do not, under any circumstances, ever write to a path within

Code:
[NSBundle mainBundle

Go and read the iPhone OS Programming Guide as I suggested earlier in this thread to find out where you can/should write to.

:mad: WELL, that was excacly what I thought too and therefore I did my implementation as before where I created a plist in the same dir as the images. That did not work and therefore I thought I better do as in the apple example. I have read the documentation but obviosly I did not understand it.
 
:mad: WELL, that was excacly what I thought too and therefore I did my implementation as before where I created a plist in the same dir as the images. That did not work and therefore I thought I better do as in the apple example. I have read the documentation but obviosly I did not understand it.

If you are reading Mac Dev Center guides it may well write into the application bundle (although this is strongly discouraged). On the iPhone this may be possible in the simulator but will fail on the device (and if it succeeded would break the code signing of the application).
 
If you are reading Mac Dev Center guides it may well write into the application bundle (although this is strongly discouraged). On the iPhone this may be possible in the simulator but will fail on the device (and if it succeeded would break the code signing of the application).

Ok, that may have been the problem. I know the problem with the iPhone. So I go back to my previous version. One question: Do I create a plist file as I create other files? I do not know if I missunderstood you before and I have read about the writeToFile:atomically: method in the documentation, and as I can see the creation of a file and then writing an NSArray or NSDic would make it a plist. This indicates that I have to create a normal file and write to it. I do this by using [fileManager createFileAtPath:filePath contents:d attributes:nil]; But what shouod be the the content here...? I have tried to define a root array and add it (containing dictionaries) but did get a warning on that...
 
You don't use NSFileManager at all. The documentation for writeToFile:atomically: is totally clear. It talks about creating the file over and over again.

So, I hope you had a nice easter holliday. I have successfully implemented the cache and the plist now and I am working on the deletion from the cache when the max size has been reached. I think there is no easy way to detect the size of a directory when using the filemanager? To go through the content of the directory every time a new img is added, seem to be a bit ineffective? What would you suggest - to save a "global" variable with the size of the cache directory? I have chosen to delete everything in the cache when the app terminates and this variable would only have to live over a current app-run...
What do you suggest?
Thanks in advance!
MACloop
 
I did have a good Easter, thanks :) I hope you did too.

I have a couple of suggestions that might work:

1) If all your images are about the same size then just use a rough estimate of size. If your average downloaded image is about 20Kb just assume that 10 are using 200Kb of space.

2) You can know how big the image is at download time (the size of the received data bytes). Add this data to your plist and you can then calculate the cache size using your in-memory metadata.
 
I did have a good Easter, thanks :) I hope you did too.
Yes I did also have a good easter :)

I have a couple of suggestions that might work:

1) If all your images are about the same size then just use a rough estimate of size. If your average downloaded image is about 20Kb just assume that 10 are using 200Kb of space.

2) You can know how big the image is at download time (the size of the received data bytes). Add this data to your plist and you can then calculate the cache size using your in-memory metadata.

My images are all the same size. I thought about setting a max_size for the plist array instead of controlling the cache-size, ie say if the plist holds more than 10 objects -> delete the last one. That would be a fast way of solving the control, but I am not sure if that is what you mean in the first suggestion. Having the string/name of the object in the plist, I can remove the file in the cache with the same name...

About your 2nd suggestion - what do you mean about "using your in-memory metadata". There is a default attribute for the file size, do you mean that I, on download, save the filesize to this attribute and then later on use this value?

MACloop
 
My images are all the same size. I thought about setting a max_size for the plist array instead of controlling the cache-size, ie say if the plist holds more than 10 objects -> delete the last one. That would be a fast way of solving the control, but I am not sure if that is what you mean in the first suggestion. Having the string/name of the object in the plist, I can remove the file in the cache with the same name...

Basically yes, this is what I was suggesting

About your 2nd suggestion - what do you mean about "using your in-memory metadata". There is a default attribute for the file size, do you mean that I, on download, save the filesize to this attribute and then later on use this value?

In my mind the plist that specified name of the object etc is saved to disk as well as being held in RAM. So the data about the on-disk cache objects is your in memory meta data. I would expect that, right now, this has the URL of the image and the filesystem path for the image. It may also have the last-update time from the server for the image in cache so you can check for staleness. I was suggesting you could add the size of the image (the size of the bytes you received when you downloaded it) so you could easily know how big the image was. You could also track the current cache size by adding/removing this number when you add/remove cache objects.
 
Basically yes, this is what I was suggesting



In my mind the plist that specified name of the object etc is saved to disk as well as being held in RAM. So the data about the on-disk cache objects is your in memory meta data. I would expect that, right now, this has the URL of the image and the filesystem path for the image. It may also have the last-update time from the server for the image in cache so you can check for staleness. I was suggesting you could add the size of the image (the size of the bytes you received when you downloaded it) so you could easily know how big the image was. You could also track the current cache size by adding/removing this number when you add/remove cache objects.


Thanks alot! Very good hints as always!
MACloop
 
Ok, everything wroks alright so far. I decided to check the file size after all and it works fine. One question:
I use the
Code:
- (void)applicationWillTerminate:(UIApplication *)application{
to reset the cache ie. I remove the directory where the caced files and the plist are saved. In case of an app crash - will this method be called as well? I have noticed that when running the app in the simulator, and when I quit it by pressing [alt + q] (I have a pc keyboard) the cache is not set to be empty the next time the app is starting. Is it safe to reset the cache the way I have done?

Thanks in advance!
MACloop
 
No, on a crash nothing gets called: it just crashes. That method is called when your application closes normally (the home button is pressed or the user answers a call or whatever).

But if your application is crashing you have bigger worries...
 
No, on a crash nothing gets called: it just crashes. That method is called when your application closes normally (the home button is pressed or the user answers a call or whatever).

But if your application is crashing you have bigger worries...

Yes I have noticed that... the question is what can I do to delete the cache when the app crashes...? If something went wrong and some garbage is written into the cache, I do not want it to be saved and case problems the next time the app is running. Should I reset the cache on start up?
 
Yes I have noticed that... the question is what can I do to delete the cache when the app crashes...?
You can't. If your code causes a crash the OS just kills you. It won't risk your misbehaving code running on. So the best solution is don't crash. Being serious if you know your code can crash work out where and why and fix it. Don't ever ship code with known crashing bugs.

Also don't write garbage into the cache. Check the quality of what you're writing before you write it!

Personally I'd want the cache to persist across application runs: it'll make the application seem faster and better over time.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.