iphone : message sent to deallocated instance - iphone

i know that kind of noob problem but it killing me for 2 days now
i have the following code
albumsVC.discList = [[NSMutableArray alloc]init];
for(id song in songs){
if([self checkIfAllFilesExist:[song objectForKey:#"fileName"]]){
[albumsVC.discList addObject:song];
}
}
and
-(BOOL)checkIfAllFilesExist: (NSString *) theFilename {
BOOL exist;
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
docPath = [ documentDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.mp3",theFilename]];
NSFileManager *fileManager = [NSFileManager defaultManager];
exist = [fileManager fileExistsAtPath:docPath];
docPath = nil;
docPath = [[NSString alloc] init];
if(!exist){
return NO;
}
return YES;
}
but it crashes after five loops (i don't know why five ? ) and it tells me that message sent to deallocated instance 0x87cdc10
on the line of
docPath = [ documentDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.mp3",theFilename]];
where docPath is NSString in the header created as nonatomic and retain ..
i can't get the problem can you help me ?

-(BOOL)checkIfAllFilesExist: (NSString *) theFilename creates memory leak.
Replace it with below code:
-(BOOL)checkIfAllFilesExist: (NSString *) theFilename {
BOOL exist;
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
self.docPath = [ documentDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.mp3",theFilename]];
NSFileManager *fileManager = [NSFileManager defaultManager];
exist = [fileManager fileExistsAtPath:docPath];
if(!exist){
return NO;
}
return YES;
}
Assuming that you have docPath property in your .h file with nonatomic, retain.

since you say it is always crashes at the fifth iteration of the loop, check the bject which comes by looping.
I mean to say , check the theFilename. Try printing the 'song' dictionary to make sure you have something in fileName key.
Also use Apurv code.

Related

File search with specific Extension Objective c

I am working on some file manipulation in iPhone project. Where i need to search files of specific extension. One option is to manually process each file & directory to find.
My Question is, Is there any simple way to do that ?
Thanks
see using NSFileManager you can get the files and bellow the condition with you can get file with particular extension, Its work in Document Directory ..
-(NSArray *)findFiles:(NSString *)extension
{
NSMutableArray *matches = [[NSMutableArray alloc]init];
NSFileManager *manager = [NSFileManager defaultManager];
NSString *item;
NSArray *contents = [manager contentsOfDirectoryAtPath:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] error:nil];
for (item in contents)
{
if ([[item pathExtension]isEqualToString:extension])
{
[matches addObject:item];
}
}
return matches;
}
use this array with your searched files.. get the return in NSArray type so use NSArray object to store this data...
i hope this helpful to you...
I have not found any thing which i could say is simple to do that & and finally i have to write my own code to do this. I am posting this here because maybe someone find this help full.
-(void)search{
#autoreleasepool {
NSString *baseDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSFileManager *defFM = [NSFileManager defaultManager];
BOOL isDir = YES;
NSArray *fileTypes = [[NSArray alloc] initWithObjects:#"mp3",#"mp4",#"avi",nil];
NSMutableArray *mediaFiles = [self searchfiles:baseDir ofTypes:fileTypes];
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [docDir stringByAppendingPathComponent:#"playlist.plist"];
if(![defFM fileExistsAtPath:filePath isDirectory:&isDir]){
[defFM createFileAtPath:filePath contents:nil attributes:nil];
}
NSMutableDictionary *playlistDict = [[NSMutableDictionary alloc]init];
for(NSString *path in mediaFiles){
NSLog(#"%#",path);
[playlistDict setValue:[NSNumber numberWithBool:YES] forKey:path];
}
[playlistDict writeToFile:filePath atomically:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:#"refreshplaylist" object:nil];
}
}
Now the recursive Method
-(NSMutableArray*)searchfiles:(NSString*)basePath ofTypes:(NSArray*)fileTypes{
NSMutableArray *files = [[[NSMutableArray alloc]init] autorelease];
NSFileManager *defFM = [NSFileManager defaultManager];
NSError *error = nil;
NSArray *dirPath = [defFM contentsOfDirectoryAtPath:basePath error:&error];
for(NSString *path in dirPath){
BOOL isDir;
path = [basePath stringByAppendingPathComponent:path];
if([defFM fileExistsAtPath:path isDirectory:&isDir] && isDir){
[files addObjectsFromArray:[self searchfiles:path ofType:fileTypes]];
}
}
NSArray *mediaFiles = [dirPath pathsMatchingExtensions:fileTypes];
for(NSString *fileName in mediaFiles){
fileName = [basePath stringByAppendingPathComponent:fileName];
[files addObject:fileName];
}
return files;
}
What you need is a recursive method so that you can process sub-directories. The first of the following methods is public; the other private. Imagine they are implemented as static methods of a class called CocoaUtil:
CocoaUtil.h:
#interface CocoaUtil : NSObject
+ (NSArray *)findFilesWithExtension:(NSString *)extension
inFolder:(NSString *)folder;
#end
CocoaUtil.m:
// Private Methods
#interface CocoaUtil ()
+ (NSArray *)_findFilesWithExtension:(NSString *)extension
inFolder:(NSString *)folder
andSubFolder:(NSString *)subFolder;
#end
#implementation CocoaUtil
+ (NSArray *)findFilesWithExtension:(NSString *)extension
inFolder:(NSString *)folder
{
return [CocoaUtil _findFilesWithExtension:extension
inFolder:folder
andSubFolder:nil];
}
+ (NSArray *)_findFilesWithExtension:(NSString *)extension
inFolder:(NSString *)folder
andSubFolder:(NSString *)subFolder
{
NSMutableArray *found = [NSMutableArray array];
NSString *fullPath = (subFolder != nil) ? [folder stringByAppendingPathComponent:subFolder] : folder;
NSFileManager *fileman = [NSFileManager defaultManager];
NSError *error;
NSArray *contents = [fileman contentsOfDirectoryAtPath:fullPath error:&error];
if (contents == nil)
{
NSLog(#"Failed to find files in folder '%#': %#", fullPath, [error localizedDescription]);
return nil;
}
for (NSString *file in contents)
{
NSString *subSubFolder = subFolder != nil ? [subFolder stringByAppendingPathComponent:file] : file;
fullPath = [folder stringByAppendingPathComponent:subSubFolder];
NSError *error = nil;
NSDictionary *attributes = [fileman attributesOfItemAtPath:fullPath error:&error];
if (attributes == nil)
{
NSLog(#"Failed to get attributes of file '%#': %#", fullPath, [error localizedDescription]);
continue;
}
NSString *type = [attributes objectForKey:NSFileType];
if (type == NSFileTypeDirectory)
{
NSArray *subContents = [CocoaUtil _findFilesWithExtension:extension inFolder:folder andSubFolder:subSubFolder];
if (subContents == nil)
return nil;
[found addObjectsFromArray:subContents];
}
else if (type == NSFileTypeRegular)
{
// Note: case sensitive comparison!
if ([[fullPath pathExtension] isEqualToString:extension])
{
[found addObject:fullPath];
}
}
}
return found;
}
#end
This will return an array containing the full path to every file with the specified file extension. Note that [NSString pathExtension] does not return the . of the file extension so be sure not to pass that in the extension parameter.
Yes we have direct method for NSArray below helps you
NSMutableArray *arrayFiles = [[NSMutableArray alloc] initWithObjects:#"a.png", #"a.jpg", #"a.pdf", #"h.png", #"f.png", nil];
NSLog(#"pathsMatchingExtensions----%#",[arrayFiles pathsMatchingExtensions:[NSArray arrayWithObjects:#"png", nil]]);
//my output is
"a.png",
"h.png",
"f.png"
Like this way you can find your specific file extension
NSString *bundleRoot = [[NSBundle mainBundle] bundlePath];
NSFileManager *manager = [NSFileManager defaultManager];
NSDirectoryEnumerator *direnum = [manager enumeratorAtPath:bundleRoot];
NSString *filename;
while ((filename = [direnum nextObject] )) {
if ([filename hasSuffix:#".doc"]) { //change the suffix to what you are looking for
[arrayListofFileName addObject:[filename stringByDeletingPathExtension]];
}
}
Use below code
NSArray *myFiles = [myBundle pathsForResourcesOfType:#"Your File extension"
inDirectory:nil];

Small amount of unwanted data going to iCloud

I don't want anything to be backed up to iCloud. However, my data cannot be recreated, so I need to place it in my application's documents directory. For each file, I did the standard:
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
if (&NSURLIsExcludedFromBackupKey == nil) { // iOS <= 5.0.1
const char* filePath = [[URL path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result == 0;
} else { // iOS >= 5.1
return [URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:nil];
}
}
I have 5mB of data in there. But my app is still registering 0.2kB in iCloud (Through settings->iCLoud->Manage Storage). So, just to be sure, I did this:
-(void)resetBackupAttributes {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSArray *fileListAct = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:nil];
for (NSString *path in fileListAct) {
[self addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:path]];
}
NSArray *paths2 = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [paths2 objectAtIndex:0];
NSArray *fileListCache = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:cacheDirectory error:nil];
for (NSString *path in fileListCache) {
[self addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:path]];
}
NSArray *paths3 = NSSearchPathForDirectoriesInDomains(NSPreferencePanesDirectory, NSUserDomainMask, YES);
NSString *preferencesDirectory = [paths3 objectAtIndex:0];
NSArray *fileListPref = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:preferencesDirectory error:nil];
for (NSString *path in fileListPref) {
[self addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:path]];
}
}
It still has 0.2kB! Is there something I am missing? Does a small amount of data gets backed up regardless... like a directory tree or something? What I really want to know is, will this 0.2kB get me rejected for not following the data storage guidelines?
ok so I will put my comment into an answer:
is it possible that your apps default plist gets backed up in the
cloud? - BUT you could hook up a proxy between your iOS (simulator)
and the internet. Just catch all outgoing data and see whats actually
get transmitted ;). e.g. SquidMan
here's the link to SquidMan just in case …
As you said you think its the plist too. You can verify that by setting a key with some junk data and see if the total amount rises. ;)

How to sort files by modified date in iOS

I used NSFileManager to retrieve the files in a folder, and I want to sort them by modified date. How to do that ?
Thanks.
What have you tried so far?
I haven't done this, but a quick look at the docs makes me think that you should try the following:
Call -contentsOfDirectoryAtURL:includingPropertiesForKeys:options:error: and specify NSURLContentModificationDateKey as one of the keys.
You'll get back an array of NSURL objects which you can then sort using an NSArray method like -sortedArrayUsingComparator:.
Pass in a comparator block that looks up the modification date for each NSURL using -getResourceValue:forKey:error:.
Update: When I wrote the answer above, -getResourceValue:forKey:error: existed in iOS but didn't do anything. That method is now functional as of iOS 5. The following code will log an app's resource files followed by a list of corresponding modification dates:
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *files = [manager contentsOfDirectoryAtURL:[[NSBundle mainBundle] resourceURL]
includingPropertiesForKeys:[NSArray arrayWithObject:NSURLContentModificationDateKey]
options:nil
error:nil];
NSMutableArray *dates = [NSMutableArray array];
for (NSURL *f in files) {
NSDate *d = nil;
if ([f getResourceValue:&d forKey:NSURLContentModificationDateKey error:nil]) {
[dates addObject:d];
}
}
NSLog(#"Files: %#", files);
NSLog(#"Dates: %#", dates);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *imageFilenames = [manager contentsOfDirectoryAtPath:documentsDirectory error:nil];
NSMutableArray *originalImage = [[NSMutableArray alloc]init];
for (int i = 1; i < [imageFilenames count]; i++)
{
NSString *imageName = [NSString stringWithFormat:#"%#/%#",documentsDirectory,[imageFilenames objectAtIndex:i] ];
}
//---------sorting image by date modified
NSArray* filelist_date_sorted;
filelist_date_sorted = [imageFilenames sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2)
{
NSDictionary* first_properties = [[NSFileManager defaultManager] attributesOfItemAtPath:[NSString stringWithFormat:#"%#/%#", documentsDirectory, obj1] error:nil];
NSDate *first = [first_properties objectForKey:NSFileCreationDate];
NSDictionary *second_properties = [[NSFileManager defaultManager] attributesOfItemAtPath:[NSString stringWithFormat:#"%#/%#", documentsDirectory, obj2] error:nil];
NSDate *second = [second_properties objectForKey:NSFileCreationDate];
return [second compare:first];
}];
NSLog(#" Date sorted result is %#",filelist_date_sorted);
static static NSInteger contentsOfDirSort(NSString *left, NSString *right, void *ptr) {
(void)ptr;
struct stat finfo_l, r_finfo_r;
if(-1 == stat([left UTF8String], &finfo_l))
return NSOrderedSame;
if(-1 == stat([right UTF8String], &finfo_r))
return NSOrderedSame;
if(finfo_l.st_mtime < finfo_r.st_mtime)
return NSOrderedAscending;
if(finfo_l.st_mtime > finfo_r.st_mtime)
return NSOrderedDescending;
return NSOrderedSame;
}
Now, later on in your code.
NSMutableArray *mary = [NSMutableArray arrayWithArray:filePathsArray];
[mary sortUsingFunction:contentsOfDirSort context:nil];
// Use mary...
Quick Method:
-(void)dateModified
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *fileList = [manager contentsOfDirectoryAtPath:documentsDirectory error:nil];
//--- Listing file by name sort
NSLog(#"\n File list %#",fileList);
int num;
//-- Listing file name with modified dated
for (NSString *s in fileList)
{
NSString *filestring = [documentsDirectory stringByAppendingFormat:#"/%#",s];
NSDictionary *filePathsArray1 = [[NSFileManager defaultManager] attributesOfItemAtPath:filestring error:nil];
NSString *modifiedDate = [filePathsArray1 objectForKey:NSFileModificationDate];
NSLog(#"\n Modified Day : %#", modifiedDate);
num=num+1;
}
}
In a category over NSFileManager:
static NSInteger contentsOfDirSort(NSURL *leftURL, NSURL *rightURL, void *ptr)
{
(void)ptr;
NSDate * dateLeft ;
[leftURL getResourceValue:&dateLeft
forKey:NSURLContentModificationDateKey
error:nil] ;
NSDate * dateRight ;
[rightURL getResourceValue:&dateRight
forKey:NSURLContentModificationDateKey
error:nil] ;
return [dateLeft compare:dateRight];
}
- (NSArray *)contentsOrderedByDateOfDirectoryAtPath:(NSURL *)URLOfFolder ;
{
NSArray *files = [self contentsOfDirectoryAtURL:URLOfFolder
includingPropertiesForKeys:[NSArray arrayWithObject:NSURLContentModificationDateKey]
options:0
error:nil];
return [files sortedArrayUsingFunction:contentsOfDirSort
context:nil] ;
}

Objective-c: How to handle errors when loading a simple txt file

I'm trying to load a simply TXT file into a NSMutableArray. My file is called NoteBook.txt. For the following purposes (handling errors), I deleted NoteBook.txt so that the App could actually NOT load it.
In the following code, I try to find out if the file exist in my Docs Folder which I'd like to load. The following code should actually NOT attempt to load the file as there isn't one. However, it does so nonetheless and I am wondering what I am doing wrong?
Imagine that the string #"NoteBook.txt" is passed to the following method and that there is no such file in the Docs Folder of the App:
-(void) loadNoteBook:(NSString *)nameOfNoteBook
{
NSLog(#"Starting method 'LoadNoteBook...'");
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents directory
//NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"NoteBook.txt"];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:nameOfNoteBook];
NSError *error;
if (filePath) { // check if file exists - if so load it:
NSLog(#"Loading notebook: %#", nameOfNoteBook);
NSString *tempTextOut = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:&error];
self.NoteBook = [[[tempTextOut componentsSeparatedByString: #"\n*----------*\n"] mutableCopy] autorelease];
}
else
{
// GENERATE mutable ARRAY
NSLog(#"Loading notebook failed, creating empty one...");
NoteBook = [[NSMutableArray alloc] init];
for (int temp = 0; temp < 6; temp++) {
[NoteBook insertObject:#"Empty" atIndex:temp];
}
}
}
Thanks for any suggestions, I'd really appreciate your help.
The problem is that you're checking if the NSString is set, not the path itself.
What you should probably do is check the path with NSFileManager fileExistsAtPath:isDirectory:
BOOL isDir;
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
if ([fileManager fileExistsAtPath:filePath isDirectory:&isDir] && !isDir) {
//file exists and is not a directory
}
You've got it already in your code:
NSString *tempTextOut = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:&error];
if(!tempTextOut) {
if(error) {
// error specific code to execute
NSLog(#"error loading file %#: %#", filePath, error);
}
// GENERATE mutable ARRAY
NSLog(#"Loading notebook failed, creating empty one...");
NoteBook = [[NSMutableArray alloc] init];
for (int temp = 0; temp < 6; temp++) {
[NoteBook insertObject:#"Empty" atIndex:temp];
}
} else {
self.NoteBook = [[[tempTextOut componentsSeparatedByString: #"\n*----------*\n"] mutableCopy] autorelease];
}
You test on filePath, which is actually just a string you've created. You don't test if there is a file behind it. Even if
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
does return an empty string you still append nameOfNoteBook to it and will if put in an if statement, testing against a non empty string will evaluate to true.

Adding an object with "text"

I'm stumped or just not finding info I need, I have an object that I want to save in an array when they select "saveDataround" button, however I can't seem to figure out how to populate the object with the text "Round": I'm getting an "Expected identifier" and "Expected , ;" errors on the first and second lines of code. Thanks in advance.
[NSString *roundChoice = [NSString stringWithFormat:#"Round"];
self.round.text = roundChoice;]
- (IBAction)saveDataround {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *recipient = [NSString stringWithFormat:#"%#/arrayChoiceRound", documentsDirectory];
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:round.text];
[array writeToFile:recipient atomically:NO];
}
Where are the first two lines of code implemented? What are they supposed to do?
Here's how I would modify the above code without more info:
// remove "[" from start of line & no need to use stringWithFormat here
NSString *roundChoice = #"Round";
// remove "]" from end of line
self.round.text = roundChoice;
- (IBAction)saveDataround {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
// use stringByAppendingPathComponent here
NSString *recipient = [documentsDirectory stringByAppendingPathComponent:#"arrayChoiceRound"];
NSMutableArray *array = [[NSMutableArray alloc] init];
// use self here (not required)
[array addObject:self.round.text];
[array writeToFile:recipient atomically:NO];
// release the array
[array release];
}