How to work around NSTask calling -[NSString fileSystemRepresentation] for arguments - objective-c

It seems that NSTask calls -[NSString fileSystemRepresentation] to encode values for each of the arguments you give it.
This can become a problem in some situations due to the fact that -fileSystemRepresentation encodes using decomposed unicode forms: for example, the a-umlaut (ä) would be encoded as U+0061 (Latin small letter a) and U+0308 (Combining diaeresis), as opposed to U+00E4 (Latin small letter a with diaeresis). The -UTF8String method, on the other hand, seems to do the opposite.
I need my NSTask arguments to be encoded using composed forms. How do I work around this issue?

A possible solution would be to subclass NSString and provide your own implementation of -fileSystemRepresentation, but unfortunately NSString is a class cluster and thus very difficult to subclass (which is also discouraged by Apple's documentation).
However, we can create a separate class that poses as an NSString, but provides its own implementation of -fileSystemRepresentation.
This can, however, create problems if NSTask does anything with the class identity of the argument objects. Currently I have no evidence that this is the case — this workaround seems to work perfectly.
Header:
// MYTaskArgument.h
#interface MYTaskArgument : NSObject
+ (instancetype) taskArgumentWithString:(NSString *)str;
#end
Implementation:
// MYTaskArgument.m
#interface MYTaskArgument ()
#property(copy) NSString *string;
#end
#implementation MYTaskArgument
+ (instancetype) taskArgumentWithString:(NSString *)str {
MYTaskArgument *ret = [[MYTaskArgument alloc] init];
ret.string = str;
return ret;
}
- (const char *) fileSystemRepresentation {
return self.string.UTF8String;
}
- (id) forwardingTargetForSelector:(SEL)aSelector {
return self.string;
}
#end

We ran in to this trying to execute shortcuts via NSTask, essentially:
shortcuts run "Foréver"
NSTask decomposes the characters (FB10036117), and then shortcuts cannot find the matching shortcut (FB10036113).
Our solution was to pre-convert the argument to UTF8, and then map the characters to octal \123 (because octal works in POSIX and thus bash, dash, and csh), and then expand the parameter within the command using printf:
/usr/bin/shortcuts run "`printf '\106\157\162\303\251\166\145\162'`"
Clearly not an ideal solution, but it works and doesn't depend on trying to fake an NSString (which is very clever, but potentially very fragile).

Related

Objective-C method parameter type-safety

If I have methods like:
- (BOOL)isValidRow:(NSDictionary*)contentVersionRow
do we really have to continually check like this at the beginning of the method
if(![contentVersionRow isKindOfClass:[NSDictionary class]]) {
// Handle unusual situation - probably return NO in this case
}
to really implement proper type-safety inside Objective-C methods? Because in theory the parameter is not guaranteed to point to an NSDictionary object, is this correct?
EDIT: So answers so far seem to indicate we should not check for this, but then what is the difference between checking for this and checking for nil parameter, which I assume we should do? Or should we not check for nil either, if it's not normally expected? Both cases cover the situation of a misbehaving caller.
Just like in C you are dealing with pointers in Objective-C. So saying NSDictionary * simply means "here's a pointer to a memory address that contains an instance of NSDictionary".
Example:
#import <Foundation/Foundation.h>
#interface Test : NSObject
- (void)useDictionary:(NSDictionary *)dictionary;
#end
#implementation Test
- (void)useDictionary:(NSDictionary *)dictionary
{
NSLog(#"Keys: %#", [dictionary allKeys]);
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
Test *test = [[Test alloc] init];
// 1: This works fine
[test useDictionary:#{#"key": #"value"}];
// 2: This will cause a compiler warning (or error depending on the options passed to the compiler)
[test useDictionary:#"not a dictionary"];
// 3: This will compile without any warnings
[test useDictionary:(NSDictionary *)#"not a dictionary"];
}
}
The 2nd and 3rd examples will cause the program to crash at runtime. So if you want to pass incorrect things to methods, you can. Usually Xcode will warn you if you have a type-mismatch.
Update about nil-checking: If it's an API-misuse to pass nil to your method, then throw an exception. That's what exceptions are for in Objective-C: to catch programming mistakes, not to handle expected runtime issues (like an unreachable network). If your method can just silently fail if nil is passed in or handle it in a sensible way, then do that instead. For example if you have a method addValue:(NSNumber *)number that adds the given value to a sum then it wouldn't be a big deal if someone called it with nil: Just don't add anything :)
Yes, but you shouldn’t.
Obj-C is a dynamic language, so it is up to each object to determine if it responds to a certain method. It is bad style to check the class of an object.
Instead, if you want to check that an object supports a selector you should use -respondsToSelector:, but only if you handle objects not responding to that selector.

Creating an Array From a CSV File Using Objective C

I'm new to coding so please excuse me if this seems like a simple question.
I'm trying to plot coordinates on a map.
I want to read a CSV file and pass the information to two separate arrays.
The first array will be NSArray *towerInfo (containing latitude, longitude and tower title)
the second, NSArray *region (containing tower title and region) with the same count index as the first array.
Essentially, I believe I need to;
1) read the file to a string.....
2) divide the string into a temporary array separating at every /n/r......
3) loop through the temp array and create a tower and region object each time before appending this information to the two main storage arrays.
Is this the right process and if so is there anyone out there who can post some sample code as I'm really struggling to get this right.
Thanks to all in advance.
Chris.
I have edited this to show an example of my code. I am having the problem that I'm receiving warnings saying
1) "the local declaration of 'dataStr' hides instance variable.
2) "the local declaration of 'array' hides instance variable.
I think I understand what these mean but I don't know how to get around it. The program compiles and runs but the log tells me that the "array is null."
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize dataStr;
#synthesize array;
-(IBAction)convert {
//calls the following program when the onscreen 'convert' button is pressed.
NSString *dataStr = [NSString stringWithContentsOfFile:#"Towers.csv" encoding:NSUTF8StringEncoding error:nil];
//specifies the csv file to read - stored in project root directory - and encodes specifies that the format of the file is NSUTF8. Choses not to return an error message if the reading fails
NSArray *array = [dataStr componentsSeparatedByString: #","];
//splits the string into an array by identifying data separators.
NSLog(#"array: %#", array);
//prints the array to screen
}
Any additional help would be much appreciated. Thanks for the responses so far.
NSString* fileContents = [NSString stringWithContentsOfURL:filename ...];
NSArray* rows = [fileContents componentsSeparatedByString:#"\n"];
for (...
NSString* row = [rows objectAtIndex:n];
NSArray* columns = [row componentsSeparatedByString:#","];
...
You'll probably want to throw in a few "stringTrimmingCharactersInSet" calls to trim whitespace.
Concerning your warnings:
Your code would produce an error (not a warning), since you need to declare your properties in the interface file before you synthesize them in the implementation. You probably remember that #synthesize generates accessor methods for your properties. Also, before using the #synthesize directive, you need to use the #property directive, also in the interface.
Here's an example:
#interface MyObject : NSObject {
NSString *myString;
}
#property (assign) NSString *myString;
#end
#implementation MyObject
#synthesize myString;
// funky code here
#end
Note that the property declaration is followed by a type (assign in this case, which is the default). There's an excellent explanation about this in Stephen G. Kochans's book: Programming in Objective-C 2.0
But assuming for argument's sake, that you omitted the correct #interface file here.
If you first declare a property in the #interface, and then declare another property in your method, using the same variable name, the method variable will take precedence over the instance variable.
In your code, it would suffice to omit the declaring of the variable name, like so:
dataStr = [NSString stringWithContentsOfFile:#"Towers.csv" encoding:NSUTF8StringEncoding error:nil];
array = [dataStr componentsSeparatedByString: #","];
I'm assuming that the core of your question is "how to parse a CSV file", not "what to do with the data once it's parsed". If that's the case, then check out the CHCSVParser library. I have used it in projects before and find it to be very reliable. It can parse any arbitrary string or filepath into an NSArray of rows/columns for you. After that, whatever you do with the data is up to you.

Generate #property implementations with C preprocessor (uppercase a character in the preprocessor)

I may be trying to abuse the preprocessor. I want to see if what I have in mind is even possible.
My class has #properties that all have the same bodies. I want to generate these bodies with a preprocessor macro. E.g.:
- (float) accelerometerSensitivity {
return [dict floatForSelector:_cmd or:1];
}
- (void) setAccelerometerSensitivity:(float) n {
[dict setFloat:n forSelector:_cmd];
[dict writeToFile:[self globalDataFilename] atomically:YES];
}
- (float) returnSpringTension {
return [dict floatForSelector:_cmd or:0];
}
- (void) setReturnSpringTension:(float) n {
[dict setFloat:n forSelector:_cmd];
[dict writeToFile:[self globalDataFilename] atomically:YES];
}
// set*ForSelector methods are in a category on NSMutableDictionary and depend on a function that translates selectors into strings:
// NSString* keyFromSelector(SEL selector);
The idea is that instead of using string literals (or string constants) as keys into the dictionary, I derive the string from the selector name. This way I am sure that the spelling of the key matches the property name and essentially get the benefit of compile-time validation of dictionary keys.
What I want to do is say something like SELECTOR_PROPERY(accelerometerSensitivity) and have it expand into the the getter and the setter. The main difficulty I have in implementing this as a pre-processor macro is generating the setter name from the property name. I need to uppercase the first letter of the property name, and I have no idea how to do that in the preprocessor.
Nope, you can't do that.
But, you can combine identifiers, so in theory you could define this as:
MACRO(A,a,ccelerometerSensitivity)
It's somewhat klugey, but it's more terse than the alternative.
Here's how I'd do it:
#define MACRO(_a) { \
const char *name = #_a; \
NSString *getterName = [NSString stringWithUTF8String:name]; \
NSString *setterName = [NSString stringWithFormat:#"set%c%s:", toupper(name[0]), (name+1)]; \
NSLog(#"getter name: %#", getterName); \
NSLog(#"setter name: %#", setterName); \
}
Basically, you stringify the macro parameter, then use a simple C function to uppercase the first letter, and use an offset to get everything after the first letter.
Now when you do this:
MACRO(foo);
MACRO(bar);
It logs this:
2011-07-19 21:21:24.798 EmptyFoundation[16016:903] getter name: foo
2011-07-19 21:21:24.800 EmptyFoundation[16016:903] setter name: setFoo:
2011-07-19 21:21:24.801 EmptyFoundation[16016:903] getter name: bar
2011-07-19 21:21:24.802 EmptyFoundation[16016:903] setter name: setBar:
HOWEVER, these are strings. You can't use them as method names. Sorry. :(
Actually, you probably really don't want to do this purely for architectural reasons.
You'll likely be better off if you:
separate the notion of setting state from persisting state. That you are causing I/O with every single tiny little change is horribly inefficient. It is also a mode rife with potential for problems; what happens if you move to a UI where the values track the UI continuously? ... you really don't want disk I/O for every time a dial/slider is tracked under a finger!
use #synthesize for all your #properties and don't even declare ivars. Leverage the tool's ability to generate exactly correct setters / getters for you.
that code looks an awful lot like you've re-invented NSUserDefaults? Use NSUserDefaults for any user preference kinda stuff.

Is there an Objective-C algorithm like `transform` of the C++ STL?

My goal is to have an array that contains all filenames of a specific extension, but without the extension.
There's an elegant solution to get all filenames of a specific extension using a predicate filter and instructions on how to split a path into filename and extension, but to combine them I would have to write a loop (not terrible, but not elegant either).
Is there a way with Objective-C (may be similar to the predicate mechanism) to apply some function to every element of an array and put the results in a second array, like the transform algorithm of the C++ STL does?
What I'd like to write:
// let's pretend 'anArray' was filled by querying the filesystem and not hardcoded
NSArray* anArray = [[NSArray alloc] initWithObjects:#"one.ext", #"two.ext", nil];
// that's what I liked to write (pseudo code)
NSArray* transformed = [anArray transform: stringByDeletingPathExtension];
// Yuji's answer below proposes this (which may be as close as you can get
// to my wish with Objective C)
NSArray* transformed = [anArray my_arrayByApplyingBlock:^(id x){
return [x stringByDeletingPathExtension];
}];
Actually, there is a very simple way. It's been around since 2003 and it is poorly named.
NSArray *array = [NSArray arrayWithObjects:#"one.ext", #"two.ext", nil];
// short solution
NSArray *transformed = [array valueForKey:#"stringByDeletingPathExtension"];
// long solution (more robust against refactoring)
NSString *key = NSStringFromSelector(#selector(stringByDeletingPathExtension));
NSArray *transformed = [array valueForKey:key];
Both produce the output:
(
one,
two
)
That's a topic called Higher Order Messaging in Cocoa, and developed by many people on the web. Start from here and try googling more. They add a category method to NSArray so that you can do
NSArray*transformed=[[anArray map] stringByDeletingPathExtension];
The idea is as follows:
[anArray map] creates a temporary object (say hom)
hom receives the message stringByDeletingPathExtension
hom re-sends the message to all the elements of anArray
hom collects the results and returns the resulting array.
If you just want a quick transform, I would define a category method:
#interface NSArray (myTransformingAddition)
-(NSArray*)my_arrayByApplyingBlock:(id(^)(id))block;
#end
#implementation NSArray (myTransformingAddition)
-(NSArray*)my_arrayByApplyingBlock:(id(^)(id))block{
NSMutableArray*result=[NSMutableArray array];
for(id x in self){
[result addObject:block(x)];
}
return result;
}
#end
Then you can do
NSArray* transformed=[anArray my_arrayByApplyingBlock:^id(id x){return [x stringByDeletingPathExtension];}];
Note the construct ^ return-type (arguments) { ...} which creates a block. The return-type can be omitted, and clang is quite smart on guessing it, but gcc is quite strict about it and needs to be specified sometime. (In this case, it's guessed from the return statement which has [x stringBy...] which returns an NSString*. So GCC guesses the return type of the block to be NSString* instead of id, which GCC thinks is incompatible, thus comes the error. )
On OS X Leopard or iOS 3, you can use PLBlocks to support blocks. My personal subjective opinion is that people who care about new software typically upgrade to the newest OS, so supporting the latest OS should be just fine; supporting an older OS won't increase your customer by a factor of two...
THAT SAID, there's already a nice open-source framework which does all I said above. See the discussion here, and especially the FunctionalKit linked there.
More addition: it's in fact easy to realize your pseudocode [array transform:stringByDeletingPathExtension].
#interface NSArray (myTransformingAddition)
-(NSArray*)my_transformUsingSelector:(SEL)sel;
#end
#implementation NSArray (myTransformingAddition)
-(NSArray*)my_transformUsingSelector:(SEL)sel;{
NSMutableArray*result=[NSMutableArray array];
for(id x in self){
[result addObject:[x performSelector:sel withObject:nil]];
}
return result;
}
#end
Then you can use it as follows:
NSArray*transformed=[array my_transformUsingSelector:#selector(stringByDeletingPathExtension)];
However I don't like it so much; you need to have a method already defined on the object in the array to use this method. For example, if NSString doesn't have the operation what you want to do as a method, what would you do in this case? You need to first add it to NSString via a category:
#interface NSString (myHack)
-(NSString*)my_NiceTransformation;
#end
#implementation NSString (myHack)
-(NSString*)my_NiceTransformation{
... computes the return value from self ...
return something;
}
#end
Then you can use
NSArray*transformed=[array my_transformUsingSelector:#selector(my_NiceTransformation)];
But it tends to be very verbose, because you need to define the method in other places first. I prefer providing what I want to operate directly at the call site, as in
NSArray*transformed=[array my_arrayByApplyingBlock:^id(id x){
... computes the return value from x ...
return something;
}];
Finally, never add category methods which do not start with a prefix like my_ or whatever. For example, in the future Apple might provide a nice method called transform which does exactly what you want. But if you have a method called transform in the category already, that will lead to an undefined behavior. In fact, it can happen that there is a private method by Apple already in the class.

Functions in Objective-C

I am trying to write a function which returns a string created from two input strings;
but when I try the function declaration
NSString Do_Something(NSString str1, NSString str2)
{
}
the compiler gets sick. (Worked fine for a different function with int arguments.)
If I change the input arguments to pointers to strings, in also gets sick.
So how do I pass Objective-C objects into a function?
All Objective-C objects being passed to functions must be pointers. Rewriting it like this will fix your compiler error:
NSString *Do_Something(NSString *str1, NSString *str2) { }
Also, please keep in mind that this is a (C-style) function and not an instance method written on an Objective-C object. If you wanted this to actually be a method on an object it would probably look something like this:
NSString *doSomethingWithString1:(NSString *)str1 string2:(NSString *)str2 { }
I say "probably" because you can name it however you want.
Functions are perfectly fine in Objective-C (and in fact earn some of the language's benefits).
See my answer to C function always returns zero to Objective C, where someone was trying what you are and had a problem with the compiler assuming return type. The structure that I set up there is important when you are using functions, just like when you are using objects and methods. Be sure to get your headers right.
To be pedantic, you're using a function definition of:
NSString *DoSomething(NSString *str1, NSString *str2) {
// Drop the _ in the name for style reasons
}
And you should be declaring it in a .h file like so:
NSString *DoSomething(NSString *str1, NSString *str2);
Just like C.
that doesn't work for me. i've just declared in the .h:
NSString *myFunction(NSDecimal *value);
and i type in the .m:
NSString *myFunction(NSDecimal *value){
//code
}
but always i get an error saying expected '(' before '*' token
now is fixed. for some reason... sorry.