What is the best way to count the number of entries in a property list?
I currently build a dictionary from the plist entries (*) and then use the dictionary's count:
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:myPlistPath];
NSDictionary *myPlistDict = (NSDictionary *) [NSPropertyListSerialization
propertyListFromData:plistXML
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format
errorDescription:&errorDesc];
NSLog(#"There are %d entries in the plist.", [myPlistDict count]);
This strikes me as unnecessarily "heavy", but I was not able to find a more efficient solution. Any ideas?
(*) targeting 10.5 and therefore using the deprecated +propertyListFromData:… class method.
Well... if you're converting to XML anyway, you could use NSXMLNode's childCount method. The documentation does suggest that it's more efficient than calling [children count], but the creation of the NSXMLNode might make this just as bad (or even worse than) the NSDictionary method.
Have you profiled? Are you working with particularly large plists? Are you requesting this count often? I say: use NSDictionary, cache the value if you request it often, and move on unless this is unacceptably slow. (Yeah, it looks ugly right now, but there are bigger things to worry about.)
Related
I need to search a folder (and all sub folders) for certain files. This needs to be done as quickly as possible and I need to be able to display a progress indicator to the user.
To display a progress indicator I would need to quickly retrieve, for example, the total number of folders underneath my folder being searched. That way I can count the sub folders as I scan them and report something useful back to the user.
Is this information available somewhere?
Note that this functionality is specifically for disks that aren't indexed using Spotlight. For Spotlight indexed drives I just run an NSMetadataQuery.
For the actual scan you can use Cocoa classes, such as NSDirectoryEnumerator, or lower-level facilities, such as fts - there are multiple ways just pick what suits you best.
The more interesting part is your progress indicator. The file system does not maintain a "child" count for a folder, i.e. a count of all the children, grandchildren, great grandchildren, etc. However the number of files on a whole volume is available, e.g. see statfs.
The number of items in a particular folder is quick and easy to determine; e.g. NSFileManager's contentsOfDirectoryAtPath:error: returns an array, the fts routines return a linked list, and you can even work it out use the hard link count - obtainable via NSURL's getResourceValue:forKey:error:. Using such methods on entry to a directory you can add its child count to a total, so as you scan the tree you maintain both the number of items processed and the currently known number that need to be processed. Your UI can be of the form "n of m" where both can increase.
If you don't like that then the number of items in a whole tree requires (pre)scanning the tree, which takes a certain amount of time (you can see this in the Finder - just select any folder, the closer to the root of the disk the better, and do a Get Info and you will see a pause while the information is collected). It is not hard to do this using any of the scanning methods mentioned above. You have to consider the time/value/memory tradeoff - e.g. while you can say produce a list of all the items in the tree (a directory enumerator will give you that) count it and then process it one item at a time you risk having a large memory footprint and a pause before anything at all happens - like the pause you see in the Finder's Get Info window).
So your goal of "quickly with progress bar" is a challenge.
HTH
Maybe you can use NSDirectoryEnumarator for that?
You can have your total number of files to check on enumerator and then you just update your progress bar while iterating.
Here's a small piece of code checking all sub folders. It already checks if URL is a directory ,so you can just ignore it.
NSFileManager *fileManager = [[NSFileManager alloc] init] ;
NSArray *keys = [NSArray arrayWithObject:NSURLIsDirectoryKey];
NSString *path = #"YOUR PATH HERE"
NSMutableArray *files = [[NSMutableArray alloc] init];
NSDirectoryEnumerator *enumerator = [fileManager
enumeratorAtURL:[NSURL fileURLWithPath:path]
includingPropertiesForKeys:keys
options:0
errorHandler:^(NSURL *url, NSError *error) {
// Handle the error.
// Return YES if the enumeration should continue after the error.
return YES;
}];
for (NSURL *url in enumerator) {
NSError *error;
NSNumber *isDirectory = nil;
if (! [url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:&error]) {
// handle error
NSLog(#"error-%#", error );
}
else if (! [isDirectory boolValue]) {
//CHECK FOR YOUR FILES ON THIS URL AND UPDATE PROGRESS INDICATOR
}
}
I need solution for osx 10.6.7+. I trying to solve problem of searching "old" files on the disk. Old Files I mean files which early 1 year.
I've created NSPredicate but NSMetadataQuery returns nothing
NSPredicate * fileTypePredicate = [NSPredicate predicateWithFormat: #"file_type == \"audio\""];
NSPredicate * accessDatePredicate = [NSPredicate predicateWithFormat: #"%K <= %#", #"kMDItemAccessedDates", timeYearBefore];
return [NSCompoundPredicate andPredicateWithSubpredicates: #[fileTypePredicate, accessDatePredicate]];
Instead of kMDItemAccessedDates also I used acess_date but also without success.
For the first one, I don't know why you expect “file_type” to be a supported metadata property.
There are two properties for an item's content type. One is kMDItemContentType, which is the immediate type of the item's content (generally as determined by its filename extension). The other is kMDItemContentTypeTree, which is an array of that type and every one of its ancestors.
To find audio files, you want to find items whose kMDItemContentTypeTree is equal to kUTTypeAudio. (Yes, equality testing will work for this, even though you really want to test whether the array contains the type. Try it in Terminal: mdfind 'kMDItemContentTypeTree == public.audio')
In your code, you should use a two-parameter format string, just like you have for the second predicate, but with == as the operator: #"%K == %#" For the parameters, pass kMDItemContentTypeTree (the key) and kUTTypeAudio (the value—in this case, content type—you're looking for).
As for the second one, I can't find any mention of kMDItemAccessedDates anywhere other exactly one other Stack Overflow question. I think the author of that question might have made that key up for his custom Spotlight importer; you can't expect to find it on a stock OS X system.
You might try kMDItemLastUsedDate instead. (Don't write it as a string literal, in #"…"—just have kMDItemLastUsedDate without any quotes around it or an # in front of it.)
Thanks To all that helped problem solved. :)
For some reason this wont work for me please help
array = [[NSMutableArray alloc] init];
inputted = [input.text doubleValue];
[array addObject:[NSNumber numberWithDouble:inputted]];
NSLog(#"%i",array.count);
where array is a NSMutableArray, inputted is a double and input is a text field
All that happens is that one saves but deletes the last one entered. how do i make it so that it saves everything entered?
You're always re-creating and re-initializing the "array" mutable array each time you go through your function so it's no wonder you are getting a result of "1" (one object in the array).
If you initialize your array once and only once, and move it out and away from the rest of that code (i.e. into a different function or whatever), then you will add additional objects to your mutable array and you'll see the count increment each time you add an object to your mutable array.
Makes sense?
I have two NSData objects
NSData *toScan = /* initialized somehow with "Hello, this world." */;
NSData *toMatch = /* initialized somehow with "this" */;
What is the best way to know the toMatch bytes are the subset of toScan bytes?
I use C-functions for this purposes at this point: something like this
strstr([[toScan identifier] bytes], [[toMatch identifier] bytes]);
// returned bytes are null-terminated
but I think there is not the best way to use C-functions in object-oriented environment...
As of Snow Leopard and iOS 4.0, NSData has -rangeOfData:options:range: which should do what you want.
It's also pretty darn fast.
In a different question, I wrote an answer containing an NSData category with a rangeOfData: method:
Elegant Algorithm for Parsing Data Stream Into Record
That'll do what you're looking for.
I have converted CGPoint To NSValue and put all the resulting values in q NSArray but when I use [NSKeyedArchiver archiveRootObject:ArrayName toFile:PointArrayFile]; it gives me error.
So what's the problem?
You don't say what problem you're seeing but in general you're probably better off using NSStringFromCGPoint and CFPointFromString to store and retrieve the points.