iOS 5: ~/Library/Caches - How to check all required files are present a very smart way? - objective-c

I guess everybody read about the recent issues with the new iOS 5.
e.g. at http://iPhoneIncubator.com/blog/data-management/local-file-storage-in-ios-5
My Magazine-App holds about 1k html/css/image/video files for every issue and I want to know if anything is missing.
So my question is how to check all required files are present a very smart way?

I would expect iOS to clean caches atomically; i.e. iOS will either clean you app's cache or it will not. It shouldn't partially remove files from your cache. However, I don't believe this is documented behaviour, so it's a bad idea to assume this.
When you download your content, you have to know what to download for each issue, right? So you already have some kind of manifest file that references every file that is needed by each magazine. You should save this manifest locally so that you can refer to it when checking for the existence of files. You can still save this in the caches directory, if it's missing, you know your cache has been at least partially cleaned.
Also, I don't believe there's any guarantee that iOS won't clean caches while your application is running. As well as checking at the point where the user opens the magazine, you should check when your application becomes active after it has been put in the background, and your code should be robust in the face of missing files (i.e. pop up a warning message instead of crashing).

You could zip all the files relating to each issue in an archive (objective-c wrapper for zlib here, to make life easier for you). That way you can make sure that the system either deletes your issue or not, without having to worry about individual files.

Related

Attaching a specific piece of non-intrusive info to a file or folder to keep a connection to a program

This is going to be a question with a lot of hypotheticals, but it's been on my mind for a while now and I finally want to get some perspectives on how to tackle this "issue". For the sake of the question, I'll make up an example requirement of how the program I want to make would work on a conceptual level without too many specifics.
The Problem
I want to create a program to keep track of miscellaneous info for files and folders. This miscellaneous info can be anything from comments, authors, to more specific info like the original source of the file (a URL for example), categories, tags, and more. All this info is kept track of in an SQLite database.
Now... how would you create a connection to the file (or folder) to the database? Whatever file is added to the program, the file should continue to operate on an independent level from the program, meaning you should be able to edit, copy, move, rename or do anything else with the file you would usually do with your OS of choice - even deleting it.
You should even be able to archive it, zip it, upload it somewhere or do other things that temporarily or permanently removes the file from your system, without losing the connection to the database. The program itself doesn't actually ever touch the files themselves, unless to generate a new entry in the database, but obviously, there should be some kind of reference in the file to a database entry in the program.
Yes, I know that if you delete the file, you would have a dead entry in the database. For now, just treat this as an unfortunate reality that can't be solved unless you incorporate the file more closely into the program.
Possible solutions and why I decided against them
Reference inside Filename
Probably the most obvious choice, you could just have a reference inside the filename to point to a database entry, for example by including the id at the start of the filename:
#1 my-example-file.txt
#12814 this-is-one-of-many-files.txt
Obviously, that goes against what I established earlier, as you would be restricted from freely renaming the file. You would always have to keep in mind to not mess with the id inside the filename, or else the connection to your program is broken. Unfortunately, that is the best bet I currently have, but I would like to avoid using that approach if possible.
Alternate Data Streams (ADS)
A pretty cool feature I recently discovered that's available on NTFS file systems, ADS allows you to store different streams of data for your files, to grossly simplify it. You could attach a data stream to your file that saves the id for the database entry in the program, and a regular user would never be able to mess directly with that.
However, since this is a feature reserved for specific file systems, there's some ugly side effects to ADS, as you can easily lose that part of the file by:
moving/copying it to a file system that doesn't support ADS, such as the file systems most often used in removable drives
uploading it to a cloud then later downloading it
moving it to another OS that might not support ADS or treats it in an unexpected way
zipping it
Thus I can't really rely on ADS either.

Objective-C - Finding directory size without iterating contents

I need to find the size of a directory (and its sub-directories). I can do this by iterating through the directory tree and summing up the file sizes etc. There are many examples on the internet but it's a somewhat tedious and slow process, particularly when looking at exceptionally large directory structures.
I notice that Apple's Finder application can instantly display a directory size for any given directory. This implies that the operating system is maintaining this information in real time. However, I've been unable to determine how to access this information. Does anyone know where this information is stored and if it can be retrieved by an Objective-C application?
IIRC Finder iterates too. In the old days, it used to use FSGetCatalogInfo (an old File Manager call) to do this quickly. I think there's a newer POSIX call for that these days that's the fastest, lowest-level API for this, especially if you're not interested in all the other info besides the size and really need blazing speed over easily maintainable code.
That said, if it is cached somewhere in a publicly accessible place, it is probably Spotlight. Have you checked whether the spotlight info for a folder includes its size?
PS - One important thing to remember when determining the size of a file: Mac files can have two "forks", the data fork, and the resource fork (where e.g. Finder keeps the info if you override a particular file to open with another application than the default for its file type, and custom icons assigned to files). So make sure you add up both forks' sizes, or your measurements will be off.

What does iOS do when an app is "Installing" and is it possible to programmatically control it?

I understand it may be unpacking some sort of compressed package into the file system (and due to the mobile nature I suppose it may be quite aggressive compression to reduce download time). But does it run any sort of preflight scripts? I suppose it does stuff like register the info.plist, add a pane in Settings.app if you've specified one, and the app's global URL and file type reception registration.
The reason why I'm interested is twofold: curiosity (would there be a way of seeing precisely what's going on? Has anyone investigated this?) and making an installation script. I'm constructing a dictionary app using Core Data (I've thought about this a lot, trust me, I want to use Core Data) and I'd like to have a way of nicely generating the Core Data store from the original XML without degrading the user experience by having some kind of "initializing app". Furthermore I'd like to deploy the dictionary compressed and then uncompress it on the device, to keep it under the 20 mb over the air download limit.
I suppose I could generate the Core Data store on my simulator or dev phone and then add it to the bundle, though that way still seems less than neat. Hence why it would be nice for iOS to handle it for me
Anyway, thoughts?
Whatever the OS does during install, you can be certain that Apple does not offer developers any hook into the operation. There is no way to run any code of your own (install script etc.) until the user first launches your app manually. So do whatever initialization needs to be done on first launch.
The .ipa packages you submit to Apple are already compressed (they are just ZIP files with another file extension) so it should not be necessary to compress a text file yourself to stay under the 20 MB limit. Compressing it twice probably won't help much in terms of file size.

Is there a way to change user desktop directory path value in Cocoa?

I know there is NSDesktopDirectory that will get me the path to current user desktop directory, but where is this path value written and is there a way to change it from my cocoa application I cannot find out.
Can anyone point me in the right direction?
Additional explanation: in Snow Leopard when I rename Desktop folder to anything whatsoever, the content of this folder still shows on desktop, so I guess OS keeps track about that folder name and locations changes and keep it as desktop folder. Does anyone know how it does that?
One way you could do this is by storing whole set of files from the user's desktop (including .DS_Store, which has positional/spatial information) into a folder in your ~/Library/Application Support/ folder, then moving other files on the ~/Desktop? This should effectively "replace" the user's desktop.
[Posted as an answer as suggested above]
I spent about 40 minutes researching this out of curiosity. Google is unhelpful in this particular scenario so I poked around my ~/Library folder. The path isn't stored anywhere there. I then dug around with command-line-fu to check flags and any other metadata I could find. Nothing helpful.
I think this is a built-in thing that uses file system references as opposed to hard-coded file paths (which is why its "Desktop" designation survives renaming). If you delete it, it creates a new one and stores the ref to that one. You'll not be able to swap it around.
I think Phil's comment is probably your best bet: move the contents of the folder rather than the folder itself. Here's my take on it:
~/Desktop/.myDesktop1 ... ~/Desktop/.myDesktop2 ... ~/Desktop/.myDesktop3
Perhaps even: ~/Desktop/.myappdesktops/1 ~/Desktop/.myappdesktops/2 ~/Desktop/.myappdesktops/3
If you move stuff into a dot-folder, it'll remain hidden but there. Active stuff stays in ~/Desktop as normal but each of your conceptual "Desktops" gets stored in a dot-file so it stays hidden.
Caveat: Time Machine. :-) Regardless of your approach, swapping out "sets" of files will potentially wreak havoc with any backup solution.
So, to answer my own question: there is no way to change the desktop path in Snow Leopard or Lion (although you van read it). The only way to switch dasktops is moving the contents itself which can be done with a set of AppleScripts to some degree :(.
The other way is this app here :)):
http://itunes.apple.com/us/app/projectdesktops/id499870251?ls=1&mt=12

Writing to files in bundle?

If you scroll down to the section 'Writing to Files and URLs' at this link, would the path varaible have to be a file on disk? Is it possible to write to a file in the bundle or must it always be deployed first?
You can write files to the application bundle as much as you'd like. Just get the path of the file through NSBundle's pathForResource:ofType: method and you can write to that file. If you want just the directory of the bundle, use resourcePath.
You don't want to do this, though. There are various reasons, but you'll break code signing, which is a big one. You should use the established conventions instead (such as writing to Library:Application Support:Your App).
EDIT: For a (possibly) more convincing reason of not to do this... When I was first learning Cocoa programming, I saved to the bundle because I didn't want to bother with the Library. It got really annoying, though, because every time you make a change to your program, you lose all of your saved data/settings for that program (assuming you're not using NSUserDefaults for preferences). I kept having to move it over from the old version to the new one. By using the Library, you don't have to worry about this.
The bundle is on disk; it's just the ".app" directory. You should not write to files in this directory, however. While currently possible on Mac, it will break code signing. On iPhone, you already can't write into your own bundle, and we should expect to see this limitation in the future on Mac. You should write your application files into various directories under ~/Library or ~/Documents as appropriate. See the File System Programming Guide for guidance.