NSDirectoryEnumerator iterated element can't compare suffix - ios

I am using NSDirectoryEnmerator to find all file with a suffix of png and jpg with following code:
NSDirectoryEnumerator *directoryEnumerator = [[NSFileManager defaultManager] enumeratorAtURL:containerURL includingPropertiesForKeys:[NSArray array] options:0 errorHandler:^BOOL(NSURL *url, NSError *error) {
// handle error
return NO;
}];
NSString *fileOrDirectory = nil;
while ((fileOrDirectory = [directoryEnumerator nextObject])) {
if([fileOrDirectory hasSuffix:#".jpg"] || [fileOrDirectory hasSuffix:#".png"]){
NSLog(#" find a image file %#", fileOrDirectory );
}
}
But there is an error said that NSURL don't have a method hasSuffix
What happened and how to make this work? what does the type of the iterated elements exactly? the above code was frequently suggested by posts and was presumed to be a NSString but it can't work

The enumeratorAtURL method works with NSURL objects rather than strings (which the exception reason clearly reveals), you can simply compare the pathExtension:
if ([fileOrDirectory.pathExtension isEqualToString:#"jpg"] ||
[fileOrDirectory.pathExtension isEqualToString:#"png"]) { ...

Related

Populated array not giving expected results

I've done a lot of object oriented programming in Java but im pretty new to objective C.
Am I doing the following properly.
Package.h
#interface Packages : NSObject
#property (nonatomic) NSArray *pictureArray;
#property (nonatomic) NSString *folderPath;
- (id)initWithPath:(NSString *)path;
-(NSArray *)getPackageItems;
-(NSString *)getFolderPath;
#end
Package.m
#implementation Packages
- (id)initWithPath:(NSString *)path
{
self = [super init];
if (self)
{
NSString *folderPath = [NSString stringWithFormat:#"%#/Objects/%#", [[NSBundle mainBundle] bundlePath], path]; //Path
NSArray *fileList = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:folderPath error: nil];
self.pictureArray = [fileList filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"pathExtension IN %#", #"png", #"(content BEGINSWITH %#)", #"object_"]];
}
for (NSString *s in self.pictureArray) {
NSLog(#"%#", s);
}
return self;
}
-(NSArray *)getPackageItems{
return self.pictureArray;
}
-(NSString *)getFolderPath{
return self.folderPath;
}
#end
Code in question inside the viewdidload of one of my views
NSMutableArray *packages = [[NSMutableArray alloc] init];
for(id key in temp){
NSLog(#"key=%# value=%#", key, [temp objectForKey:key]);
Packages *tmp = [[Packages alloc] initWithPath:[temp objectForKey:key]];
[packages addObject:tmp];
}
so this for loop is iterating over a plist that I have. A series of paths.
for each path, it is creating an instance of Packages and adding it to an array of packages.
However, when do I do this
NSArray *something = [packages[1] getPackageItems];
I get an empty result back no matter what!
and even when I do this
NSLog(#"%#", [packages[0] getFolderPath]);
It prints out null.
What am I doing wrong.
EDIT
This is how the picture folder looks like
The code to pull it use to work when all of the pictures where in the Objects directory without any of the sub directories. I hope I edited the code properly to handle the sub dir
Edit 2
NSError *error;
NSArray *fileList = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.folderPath error: &error];
NSLog(#"%#, %#", fileList , error);
on the line
NSString *folderPath = [NSString stringWithFormat:#"%#/Objects", [[NSBundle mainBundle] bundlePath], path]; //Path
which successfully prints
2014-03-23 21:25:32.200 ScrollBar[4475:60b] (
"object_eyes_0_0.png",
"object_eyes_10_1.png",
"object_eyes_10_2.png",
"object_eyes_10_3.png",
"object_eyes_10_4.png",
"object_eyes_10_5.png",
"object_eyes_10_6.png",
"object_eyes_10_7.png",
When I do
NSString *folderPath = [NSString stringWithFormat:#"%#/Objects/%#/objects", [[NSBundle mainBundle] bundlePath], path]; //Path
which outputs
2014-03-23 21:27:46.951 ScrollBar[4496:60b] (null), Error Domain=NSCocoaErrorDomain Code=260 "The operation couldn’t be completed. (Cocoa error 260.)" UserInfo=0x8e2dda0 {NSUnderlyingError=0x8e2d020 "The operation couldn’t be completed. No such file or directory", NSFilePath=/Users/dev/Library/Application Support/iPhone Simulator/7.1/Applications/8B55D440-5727-471E-9BCC-1513C190740E/ScrollBar.app/Objects/object_eye_0_0/objects, NSUserStringVariant=(
Folder
)}
But as you can see in the image above, the file structure does exist.
Solution:
I accepted an answer even though it wasnt the real answer, it was the clear path to find out what was wrong.
The problem was that you can not have referenced folders containing sub folders using the code provided. I just many folders.
in your initWithPath:, you have NSString *folderPath = which declare a local variable and assign some value to it. However you did not save the value so self.folderPath is nil
- (id)initWithPath:(NSString *)path
{
self = [super init];
if (self)
{
self.folderPath = [NSString stringWithFormat:#"%#/Objects/%#", [[NSBundle mainBundle] bundlePath], path];
NSArray *fileList = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.folderPath error: nil];
self.pictureArray = [fileList filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"pathExtension IN %#", #"png", #"(content BEGINSWITH %#)", #"object_"]];
}
for (NSString *s in self.pictureArray) {
NSLog(#"%#", s);
}
return self;
}
for logging error
NSError *error;
NSArray *fileList = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.folderPath error: &error];
NSLog(#"%#, %#", fileList , error);
NEVER do NSLog([Someclass someMethod]), use NSLog(#"%#", [Someclass someMethod]) instead

Attempt to rename file in Documents directory has error "file:/..."

Below is the code I have written to change the name of any file stored in an iOS device "Documents" directory.
When renaming the file using this code, the prefix resolves to...
"file:/localhost/private/var/mobile/Applications/.../Documents/"
instead of the correctly formatted...
"file://localhost/private/var/mobile/Applications/.../Documents/"
I am losing a slash, and so the rename method fails!!!
I have rewritten this for both NSString and NSURL formats, and both methods present the identical error. I have tested this using the iOS Simulator and on device, and both tests present the identical error.
I suspect I am overlooking something simple, but cannot figure what it is - any help please?
- (void)alterFileNameOrExtension {
NSError *errorMove = nil;
NSError __autoreleasing *error = nil;
//note below - entity attribute document.dStringURL has a data type NSString
NSString *file = [document.dStringURL lastPathComponent];
NSString *fileName = [file stringByDeletingPathExtension];
NSString *fileExtension = [file pathExtension];
NSString *fileNameNew = nil;
//note below - self.tempFileComponent, self.tempFileName & self.tempFileExtension
//note below - are set in the (IBAction) method textFieldDidEndEditing:
//note below - self.tempFileComponent determines whether the user is attempting to change the file name or the file extension
if (self.tempFileComponent == 1) {
fileNameNew = [[self.tempFileName stringByAppendingPathExtension:fileExtension] stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
} else if (self.tempFileComponent == 2) {
fileNameNew = [fileName stringByAppendingPathExtension:self.tempFileExtension];
} else {
NSLog(#"%# - %# - attempt to determine tempFileComponent has (possible undefined) E~R~R~O~R: %#_", self.className, NSStringFromSelector(_cmd), error.localizedDescription);
}
NSString *filePath = [document.dStringURL stringByDeletingLastPathComponent];
NSString *filePathNew = [filePath stringByAppendingPathComponent:fileNameNew];
BOOL move = [[NSFileManager defaultManager] moveItemAtPath:document.dStringURL toPath:filePathNew error:&errorMove];
if (!move) {
//handle error
} else {
//complete process
}
}
#
With assistance from #Mario, I have adjusted my code and include the working version below for the benefit of others...
#
NSError *errorMove = nil;
NSError __autoreleasing *error = nil;
NSString *file = [document.dStringURL lastPathComponent];
NSString *fileName = [file stringByDeletingPathExtension];
NSString *fileExtension = [file pathExtension];
NSString *fileNameNew = nil;
if (self.tempFileComponent == 1) {
fileNameNew = [self.tempFileName stringByAppendingPathExtension:fileExtension];
} else if (self.tempFileComponent == 2) {
fileNameNew = [fileName stringByAppendingPathExtension:self.tempFileExtension];
} else {
NSLog(#"%# - %# - attempt to determine tempFileComponent has (possible undefined) E~R~R~O~R: %#_", self.className, NSStringFromSelector(_cmd), error.localizedDescription);
}
NSURL *fileURLOld = [NSURL URLWithString:document.dStringURL];
NSURL *fileURLPrefix = [fileURLOld URLByDeletingLastPathComponent];
NSURL *fileURLNew = [fileURLPrefix URLByAppendingPathComponent:fileNameNew];
BOOL move = [[NSFileManager defaultManager] moveItemAtURL:fileURLOld toURL:fileURLNew error:&errorMove];
if (!move) {
//handle error
} else {
//complete process
}
The NSString path manipulation methods like stringByAppendingPathComponent expects file paths not URLs. It will remove double slashes as this is not a valid file path (although it is a valid URL).

Song doesn't play when method called from another class

I'm trying to play a song in my application. When the the code to play a song is put right away in the controller it runs good.
But when i put the code in a class, call the class then call the method to play the song, nothing happens ? If someone have a clue please feel free to help.
here is the code to play a song
-(void)randomSound{
NSLog(#"sound");
NSString * path;
NSError * err;
NSString *name;
NSArray *names = [[NSArray alloc] initWithObjects:#"1up.wav", #"mario02.dsp.wav", #"mario04.dsp.wav", #"mario06.dsp.wav", #"mrf.dsp.wav", nil];
name = [names randomObject];
path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:name];
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
NSURL * url = [NSURL fileURLWithPath:path];
self.snd = [[AVAudioPlayer alloc] initWithContentsOfURL:url
error:&err] ;
if (! self.snd) {
NSLog(#"data named '%#' had error %#", name, [err localizedDescription]);
} else {
NSLog(#"playing");
[self.snd prepareToPlay];
[self.snd play];
}
} else {
NSLog(#"data file '%#' doesn't exist at '%#'", name, path);
}
}
The way i call the method
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"YAHOO"])
{
YahooViewController *YH = [[YahooViewController alloc] init];
[YH randomSound];
}
The random method in case someone would like to know whats in it
-(id)randomObject {
NSUInteger myCount = [self count];
if (myCount)
return [self objectAtIndex:arc4random_uniform(myCount)];
else
return nil;
}
After discussion in comments it was identified the issue was URL encoding.
Check out this question / answer which will show you how to URLEncode a string:
How do I URL encode a string

Looking for a Logic Solution to Build Dynamic Filepath in iOS

I have a file structure which is being built in the following manner.
1) Each user is provided an ID in MySQL database.
2) When user uploads an image from iphone the image is placed in the following directory:
`../images/[USER_ID]/[IMAGE_NUMBER].jpg`
3) In the path noted above, [IMAGE_NUMBER] is generated based upon the submission value. So the first image uploaded will be titled 1.jpg, the second as 2.jpg etc…
So to build a sample directory for the purposes of this question the structure could look something like this:
../images-->
../10/1.jpg
../10/2.jpg
../10/3.jpg
../11/4.jpg
../11/5.jpg
../10/6.jpg
../11/7.jpg
So in this case, User #10 uploaded 3 images, then logged out. Along comes User #11 and she uploads 2 images before logging out. And finally, User #10 logs back in and uploads another image.
Okay now that we have the summary of out the directories are being generated and images are dynamically input, let me get to the ultimate question. I would like to be able to display thumbnails of all the images on a view in the iphone when a user clicks a button that we will call btnRefresh
Here is the method that is associated with btnRefresh:
-(IBAction)btnRefreshTapped
{
[self refreshStream];
}
-(void)refreshStream {
[[API sharedInstance] commandWithParams:[NSMutableDictionary dictionaryWithObjectsAndKeys:
#"stream",#"command",
nil]
onCompletion:^(NSDictionary *json) {
[self showStream:[json objectForKey:#"result"]];
}];
}
As you can see this is referencing the API sharedInstance here is that method:
+(API*)sharedInstance
{
static API *sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
sharedInstance = [[self alloc] initWithBaseURL:[NSURL URLWithString:kAPIHost]];
});
return sharedInstance;
}
and finally we come full circle to the URLWithString value:
-(NSURL*)urlForImageWithId:(NSNumber*)IdPhoto isThumb:(BOOL)isThumb {
int IdValue = [[user objectForKey:#"id"] intValue];
NSString* urlString = [NSString stringWithFormat:#"%#/%#upload/%d/%#%#.jpg",
kAPIHost, kAPIPath, IdValue, IdPhoto, (isThumb)?#"-thumb":#""
];
return [NSURL URLWithString:urlString];
}
So, herein lies my problem. As this is currently being defined I can only see the images of the user that is logged into the app when they click btnRefresh. The other image locations show up as greyed out images due to the broken URLs. So, how can I redefine IdValue to cycle through available folders and pull the associated images for display?
I know this is a complex problem so thank you to putting some brainpower into a solution.
I don't know is it what you asking but you can get all files from the directory via this code:
NSArray *contents = [fileManager contentsOfDirectoryAtURL:YourURL
includingPropertiesForKeys:#[] // <-Add key/s if needed
options:NSDirectoryEnumerationSkipsHiddenFiles error:nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"pathExtension == 'jpg'"];
for (NSURL *fileURL in [contents filteredArrayUsingPredicate:predicate])
{
// Enumerate each .jpg file in directory
}
You can specify images directory and you should be able to find the images and get url to that.
The other way is recursively enumerate files in directory, it's more powerful and it can be amended to your requirement:
NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtURL:YOURURL
includingPropertiesForKeys:#[NSURLNameKey, NSURLIsDirectoryKey] // <-Add more key if needed
options:NSDirectoryEnumerationSkipsHiddenFiles
errorHandler:^BOOL(NSURL *url, NSError *error)
{
NSLog(#"Error %#", error);
}];
NSMutableArray *mutableFileURLs = [NSMutableArray array];
for (NSURL *fileURL in enumerator) {
NSString *filename;
[fileURL getResourceValue:&filename forKey:NSURLNameKey error:nil];
NSNumber *isDirectory;
[fileURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil];
if (![isDirectory boolValue]) {
[mutableFileURLs addObject:fileURL];
}
}
Hope one of those will be usefull for you.
Modifying what Greg just answered so that you don't have to iterate the array.
NSArray *paths = [fileManager contentsOfDirectoryAtURL:YourURL
includingPropertiesForKeys:#[]
options:NSDirectoryEnumerationSkipsHiddenFiles error:nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:
[NSString stringWithFormat:
#"self ENDSWITH '/filename.jpg'"]];
NSArray *filteredArray = [paths filteredArrayUsingPredicate:predicate];
if ([newarray lastObject]) {
//you have your path here
}
filename.jpg is the IdPhoto.jpg in your code. This code with work because of the type of data you have. I have included "/" in filename.jpg so that there are no issues in detecting 110.jpg vs 10.jpg.

CHCSV Parser error: No known class method for selector 'arrayWithContentsOfCSVFile:encoding:error:'

When attempting to use the CHCSV parser like this:
#import "CHCSVParser.h"
....
- (IBAction)hi:(id)sender {
NSString *path = [[NSBundle mainBundle] pathForResource:#"nood" ofType:#"csv"];
NSError *error = nil;
NSArray *rows = [NSArray arrayWithContentsOfCSVFile:path encoding:NSUTF8StringEncoding error:&error];
if (rows == nil) {
//something went wrong; log the error and exit
NSLog(#"error parsing file: %#", error);
return;
}
}
I get the error:
No known class method for selector arrayWithContentsOfCSVFile:encoding:error:
I have included the CHCSV header but this error still happens.
This question is the exact same as this one but it never got answered so please don't mark it as a duplicate.
The header from github appears to have no such method. Your choices appear to be:
+ (instancetype)arrayWithContentsOfCSVFile:(NSString *)csvFilePath;
+ (instancetype)arrayWithContentsOfCSVFile:(NSString *)csvFilePath options:(CHCSVParserOptions)options;
Note that neither has an encoding: argument.
As this question is asked long back but still i will add
These methods has been deprecated which Dev has already rewritten in .h file.
Instead you have to use
- (IBAction)hi:(id)sender {
NSString *path = [[NSBundle mainBundle] pathForResource:#"nood" ofType:#"csv"];
NSArray *rows = [NSArray arrayWithContentsOfCSVURL:[NSURL fileURLWithPath:path] options:options];
if (rows == nil) {
//something went wrong; log the error and exit
NSLog(#"error parsing file: %#", error);
return;
}
}

Resources