Objective-C: Extract filename from path string - objective-c

When I have NSString with /Users/user/Projects/thefile.ext I want to extract thefile with Objective-C methods.
What is the easiest way to do that?

Taken from the NSString reference, you can use :
NSString *theFileName = [[string lastPathComponent] stringByDeletingPathExtension];
The lastPathComponent call will return thefile.ext, and the stringByDeletingPathExtension will remove the extension suffix from the end.

If you're displaying a user-readable file name, you do not want to use lastPathComponent. Instead, pass the full path to NSFileManager's displayNameAtPath: method. This basically does does the same thing, only it correctly localizes the file name and removes the extension based on the user's preferences.

At the risk of being years late and off topic - and notwithstanding #Marc's excellent insight, in Swift it looks like:
let basename = NSURL(string: "path/to/file.ext")?.URLByDeletingPathExtension?.lastPathComponent

Related

Objective-C equivalent of Swift "\(variable)"

The question title says it all, really. In swift you use "\()" for string interpolation of a variable. How does one do it with Objective-C?
There is no direct equivalent. The closest you will get is using a string format.
NSString *text = #"Tomiris";
NSString *someString = [NSString stringWithFormat:#"My name is %#", text];
Swift supports this as well:
let text = "Tomiris"
let someString = String(format: "My name is %#", text)
Of course when you use a format string like this (in either language), the biggest issue is that you need to use the correct format specifier for each type of variable. Use %# for object pointers. Use %d for integer types, etc. It's all documented.
#rmaddy's Answer is the gist of it. I just wanted to follow up on his comment that "It's all documented". Well, these symbols like %# and %d are called String Format Specifiers the documentation can be found at the following links.
Formatting String Objects
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Strings/Articles/FormatStrings.html
String Format Specifiers
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265-SW1
Just telling us noobs "It's all documented" isn't very helpful because often (if you're like me) you googled to find this stackoverflow post at the top of the SEO. And taking the link in hopes of finding the original documentation!

stringByAddingPercentEscapesUsingEncoding was deprecated in 9.0 .How to do this?

I'm a junior developer, and I got a code for this:
(NSString *)encodedStringFromObject:(id)object {
return [[object description] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}
But in 9.0 have to use stringByAddingPercentEncodingWithAllowedCharacters.
How Could I transfer this code ?
I need help, Thanks!
If you want just fast example look at this code:
NSString * encodedString = [#"string to encode" stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
Also check List of predefined characters sets
If you want explanation read the documents or at least this topic: How to encode a URL in Swift
URL = [[NSString stringWithFormat:#"%#XYZ",API_PATH]stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
You'd read the spec for both functions. Then you would find out for what purpose characters are replaced with escape sequences. From there you would find out the set of allowed characters, which must be documented somewhere.
That's an essential part of changing from junior to normal to senior developer: Find out exactly what your code is supposed to do, which should be defined somewhere, and then make it do what it should do.
stringByAddingPercentEscapesUsingEncoding is probably deprecated because it doesn't know which characters are allowed and sometimes gives the wrong results.
You can use stringByRemovingPercentEncoding instead of stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding
[#"string" stringByRemovingPercentEncoding];
Here is solution to do in Swift
var encodedString = "Hello, playground".addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed)

Resolve real path in NSString, without ".." (previous directory references)

OK, let me explain...
I have an NSString and a path stored in it, like this (as weird as it may look) :
/A/B/C/../D/../E/F
which is practically the same as :
/A/B/E/F
What I want is to convert the first path format (with the ..s in it) the the second format.
Is there any built-in Cocoa function for something like that?
Any ideas?
Just found it! :-)
-(NSString *)stringByStandardizingPath;
Returns a new string made by removing extraneous path components from
the receiver.
NSString class reference.

how to convert a path in NSString to CFURLRef and to FSRef*

I need to use several functions requiring CFURLRef and FSRef* and for the moment I just have a path stored in an NSString.
What is the (most efficient) way to perform this conversion?
Thanks in advance for your help,
A path can be easily converted to a CFURL by using NSURL, which it is toll-free bridged with. There is also a CFURL function which will give you a FSRef for it. This code will give you both, given an NSString named thePath.
CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:thePath];
FSRef fileRef;
CFURLGetFSRef(url, &fileRef);
If you already have a valid pointer to a FSRef, you can pass it to CFURLGetFSRef directly.

How to use string hash more than once?

My application generates loads of images and in order to save memory, I write these files to the temporary directory and read them when needed. I write two versions of the same image to the tmp folder one the thumbnail version at lower resolution and the other is full size. To make the file names unpredictable, I add a string hash at the end.
For instance I want to have two images one called "ThumbnailImage.fgl8bda" and the other "FullImage.fgl8bda"
This is the code I use:
NSString *fileName = #"Image.XXXXXXX";
NSString *thumbName = [#"Thumbnail" stringByAppendingFormat:#"%#", fileName];
NSString * thumbPath = [self writeToTempFile:thumbNailImage andName: thumbName];
NSString *fullName = [#"Full" stringByAppendingFormat:#"%#", fileName];
NSString *fullPath = [self writeToTempFile:fullImage andName: fullName];
However, the two files come out with different names, i.e. each time I use the fileName variable the hash is regenerated. For instance, my two images are called "ThumbnailImage.jhu078l" and "FullImage.ksi9ert".
Any idea how I can use the same hash more than once?
It is generally not safe to reuse a temporary file name suffix, because even if you can ensure A.ashkjd does not exist, there is a chance B.ashkjd is occupied.
You could construct a folder and store the two images in it, e.g.
char tmpl[] = "Image.XXXXXX";
char* res = mkdtemp(tmpl);
if (res != NULL) {
NSString* dirName = [NSString stringWithUTF8String:res];
NSString* thumbPath = [dirName stringByAppendingPathComponent:#"Thumbnail.png"];
[thumbImage writeToFile:thumbPath atomically:YES];
NSString* fullPath = [dirName stringByAppendingPathComponent:#"Full.png"];
[fullImage writeToFile:fullPath atomically:YES];
}
(Note: you need to remove the folder manually.)
#KennyTM has a correct solution, but he didn't explain the cause.
writeToTempFile does not use a hash to fill in the unique part of the name. Instead, it uses a new unique random string for each call.
#TimG
It doesn't really make a difference. That too ends up in different names.
When I write
NSString *fileName = #"Image.XXXXXXX";
The XXXXXXX part of the fileName is replaced by 7 random characters so that the filenames are not predictable.
Cheers
I'm new to objc so apologies if this is a stupid suggestion. What happens if you use stringByAppendingString instead of description that you're invoking:
NSString *thumbName = [#"Thumbnail" stringByAppendingString:fileName];
I don't see why the two aren't equivalent for this usage, but still.
Also, how/where are you generating the hash?
EDIT
#ar06 I think you're saying that your (I'm assuming it's your) writeToTempFile method does a replace on the XXXXX' in the fileName parameter to a random value. If so then there's your problem - it generates a new random every time it's called, and you're calling it twice. The code fragment you posted does work, because fileName is immutable; it will save with a 'XXXXX' extension.
Do you need to refer to these random suffixes later? Whatever mechanism you use for tracking them could be also used by writeToTempFile to attach the same value to the thumb and the fullsize.
FWIW I agree that Kenny's approach is better since you can't guarantee uniqueness.