Problem declaring and calling internal metthods - objective-c

How do I declare and use small helper functions inside my normal methods ?
In on of my objective-c methods I need a function to find an item within a string
-(void) Onlookjson:(id) sender{
NSString * res = [[sender gstring] copy];
persInfoBirth.text = getKeyValue(res, #"Birth");
}
I came up with a normal C type declaration for helper function getKeyvalue like this
NSString * getKeyvalue(NSString * s, NSString * key){
NSString *trm = [[s substringFromIndex:2] substringToIndex:[s length]-3];
NSArray *list = [trm componentsSeparatedByString:#";"];
//....
NSString res;
res = [list objectAtIndex:1];
//...
return res;
}
Example input string in s:
s=#"{ Birth = "1910"; Death = "1936"; }";
Anyway I get an exception "unrecognized selector sent to instance" for any of the two first lines in the helper function
How do I declare helper functions that are just to be used internally and how to call them safely ?
regards
Martin

Is this the real code? Do you get zero errors and warnings from the compiler? You must not ignore compiler warnings and you should turn on the Static Analyser in addition to the standard warnings.
There are many things wrong with the above code, most of which are nothing todo with declaring and calling methods. There is no way the above code could compile so maybe it pasted incorrectly or something..
Anyway.. declaring and using methods. Why are using a c function? Unless you have a good reason why not use Objective-c ? If you do have a good reason to use a C function the your definition should be:-
NSString *getKeyvalue( NSString *s, NSString *key ){
...
}
note the arguments. As NSString instances reside in the heap (not on the stack) you always want to pass pointers to them.
You then need to put the declaration in the header file:-
NSString *getKeyvalue( NSString *s, NSString *key )
EDIT:
In Objective-c there is no distinction between normal methods and helper methods, there is only one kind, and you have aleray written one
- (void)onLookJson:(id)sender { .. }
Taking it apart..
All methods begin with + or –, indicating Class method or Instance method. As you are familiar with C++ i guess you know what this means.
(void) is the return type. ie this method doesn't return a value. If it did it might look like (float) or (NSString *) or (id).
onLookJson: is the method name and the method takes 1 argument. Notice that the ':' is actually part of the name. This method is never is any circumstance just 'onLookJson'. An argument must always follow the :, so a method that doesn't take any arguments must not have one.
Ex
- (NSString *)fullName { .. }
This is an instance method, for example of a Person Class, you would call it like:-
NSString *theName = [aPerson fullName];
So
a method name that takes no
arguments is like 'speak'
a method
name that takes 1 argument is like
'speakTo:'
a method name that takes 2
arguments is like 'speakTo: language:'
a method name that takes 3
arguments is like 'speakTo: language: volume:'
etc.
All that is left is to put in the argument types and names.
Your function definition:
NSString *getKeyvalue( NSString *s, NSString *key ){
would become..
- (NSString *)getValue:(NSString *)s key:(NSString *)key { .. }
again, you need to declare it in the header or you will get a compiler warning.
- (NSString *)getValue:(NSString *)s key:(NSString *)key;

Related

Implicit ownership qualifier for parameters/return type is always __strong?

Since in projects with automatic reference counting NSString * aString; means implicitly NSString * __strong aString;. Does it also count for the parameters and return types?
Is
- (NSString *)doubleString:(NSString *)aString {
return [NSString stringWithFormat:#"%#%#", aString, aString];
}
the same compiled code as
- (NSString * __strong)doubleString:(NSString * __strong)aString {
return [NSString stringWithFormat:#"%#%#", aString, aString];
}
and in every similar method?
Short answer: Yes. Both variants produce the same compiled code, as can be verified
by "Product -> Perform Action... -> Assemble ..." from the Xcode menu.
Longer answer: (The following references and citations are from the Clang/ARC documentation.)
Your question about the return value. According to
"4 Ownership qualification",
qualifiers like __strong and __weak apply to locations in memory where a pointer
to an object is stored, and they specify the semantics when loading from or storing to
an lvalue (4.2 Semantics).
The return value of a method is not such a location in memory (it is not an lvalue),
therefore the concept of ownership qualification does not apply here.
It makes not differences if the method is declared as returning (NSString * __weak) or (NSString * __strong), there is no difference in the compiled code.
A slightly different question is whether the caller owns the
returned object (it has a +1 retain count) or not. This depends by default on the method name, as explained in "3.2.2 Retained return values"
and "3.2.3 Unretained return values".
Your question about the parameters. Declaring the parameter as
(NSString * __strong) is identical to (NSString *). This can already be seen
from the Xcode autocompletion (where the "__strong" qualifier is not shown), but
also from the generated Assembly code.
This does not mean that arguments are retained when calling a method.
By default, they are not, as explained in
"3.2 Retainable object pointers as operands and arguments".
If an parameter is declared as __weak, it seems (from the Assembly code) that a temporary weak reference is created in the method, i.e.
- (NSString *) doubleString:(NSString * __weak)aString {
return [NSString stringWithFormat:#"%#%#", aString, aString];
}
is essentially the same as
- (NSString *) doubleString:(NSString *)aString {
NSString *__weak wString = aString;
return [NSString stringWithFormat:#"%#%#", wString, wString];
}
But I was not able to find a definite reference for this.

Constant value of NSString representation

I have a PList where I load a couple of rows of data in a dictionary. I want to add the a line like
<key>StandardValue</key>
<string>STANDARDVALUEFORCERTAININSTANCE</string>
Now when I read out the values I get a NSString. How can I get the value of the constant that I previously defined with
#define STANDARDVALUEFORCERTAININSTANCE 123
Is there a way to get the constant representation of a string? So essentially to parse it?
What you want to do isn't exactly possible. The constants created with #define only exist at compile-time, and at run time there is no way to access them by name - they have been converted to the constant value already.
One alternative that might exist is to define a number of methods that return constant values, say in a Constants class. Then, at run time, load the name of the method from the plist and call it using NSSelectorFromString() and performSelector:.
However, a possible issue with this is that for safety with performSelector: you'd have to rewrite all your constants as Objective-C objects (since performSelector: returns type id). That could be quite inconvenient.
Nevertheless, here is an example implementation of the Constants class:
#implementation Constants : NSObject
+ (NSNumber *)someValueForACertainInstance
{
return #123;
}
#end
And example usage:
NSDictionary *infoDotPlist = [[NSBundle mainBundle] infoDictionary];
NSString *selectorName = infoDotPlist[#"StandardValue"];
SEL selector = NSSelectorFromString(selectorName);
NSNumber *result = [Constants performSelector:selector];
And how the selector name would be stored in the info plist:
<key>StandardValue</key>
<string>someValueForACertainInstance</string>
You can't do it this way. I suggest a nice alternative: KVC.
You declare this variable as class instance:
#property (nonatomic,assign) int standardValueForCertainInstance;
Then you get the value with valueForKey:
NSString* key= dict[#"StandardValue"];
int value= [[self valueForKey: key] intValue];

NSString blowing my mind away

I have three NSString properties declared like this:
#property(nonatomic,retain) NSString *currentPassword;
#property(nonatomic,retain) NSString *newPassword;
#property(nonatomic,retain) NSString *confirmPassword;
I initialize them in a viewDidLoad method:
currentPassword = [[NSString alloc]init];
newPassword = [[NSString alloc]init];
confirmPassword = [[NSString alloc]init];
The funny thing is that they are the same object after initialize them as different objects!
Is this some kind of compiler optimization?
Thank you
Is this some kind of compiler optimization?
Not quite. It's a special case value for a constant, and an optimization of a common concrete immutable type/value which has been implemented by the NSString class.
NSString is immutable. There's no reason multiple instances of the same empty string are needed. In such simple cases, -[NSString init] can take the form:
static NSString* const EmptyNSString = #"";
- (id)init
{
self = [super init];
[self release];
return EmptyNSString;
}
similarly, + [NSString string]:
+ (id)string
{
return EmptyNSString;
}
So there are a few static immutable objects which are used this way where it makes sense. Other obvious examples include + [NSArray array] and + [NSNumber numberWithBool:].
Each one of these constants can represent what would have been many many many thousands of unique allocations produced during your program's execution.
This happens to work because NSString as a class cluster: You are returned an object of one of many opaque types which implements the interface declared by NSString. Therefore, a NSMutableString type could then implement init appropriately:
- (id)init
{
self = [super init];
if (nil != self) { ... }
return self;
}
Finally, you should in almost all cases declare your NSString properties as copy.
As NSString objects are immutable (i.e. cannot be changed after they are created) and there's no sense in creating several different instances of the same immutable strings, system tries to reuse existing objects whenever possible.
Using constructor with no parameters may be one of examples. You can also check that +stringWithString: (and -initWithString:) also return the (retained) parameter string, and copy method in NSString is equivalent to retain.
Remember that optimization is only possible because we know NSString instance is not going to change and the same tests with NSMutableString most likely will to create new string instances.
P.S. About NSAssert usage:
NSAssert Generates an assertion if a given condition is false.
So your assert condition should be reversed:
NSAssert(currentPassword && newPassword && confirmPassword,#"nil field");
When you have NSString as a property you should specify the attribute 'copy' instead.
NSString is defined as an immutable type, so whenever the compiler can optimize things by combining identical strings, it should. if you use #"myString" in two separate places in your code, they will be referencing the very same object. #"" strings are of class NSConstantString

Objective C question: method won't return a string

This is my first question so please forgive me if it's obvious. I learned to program in Pascal a few years ago, so my terminology may be off. I've looked at a bunch of postings, but nothing seems to address my basic problem.
I have a lookup table that I use to convert decimals back into fractions. I am calling this method...
-(void) convertToFractions:(float *)float2 aString:(NSMutableString *) myString;
...with this..
[self convertToFractions:&float1 aString:outputFraction];
The idea is that float2 is the decimal that I pass to the method, and myString is the fraction returning.
This runs after the lookup:
myString = [NSString stringWithString:[[decimalInchArray objectAtIndex:x]objectAtIndex:1]];
NSLog(#"myString = %#",myString);
The log shows myString is the correct fraction i.e. myString is correctly displaying the fraction I want to return, but outputFraction is null.
I think it's a pointer issue. I tried *myString, but the compiler throws an error (incompatible types).
Any suggestions are really appreciated.
You want to change the output of your convertToFractions method from void to NSString.
It's returning null because the return type of your method, is void, so it returns nothing.
The return type of an Objective-C method is in the parenthesis, at the beginning of the method name.
Here,s an example, but I don't see where you define convertToString so, I'll use pseudocode.
- (NSString *) convertToFractions:(float *)float2{
NSString *fraction = *some code to lookup fraction from table;*
return fraction;
}
myString = [self convertToFractions:(float *)float2];
EDIT:
As others have suggested, you should give Objective-C a fresh look. I suggest you read this Objective-C Primer written by Apple.
Where do you define your outputFraction? Nowhere in the code above you mention it.
At a guess your conversion method is declared as (void) meaning it will not return anything. If you need it to return the result as a NSString declare it like
-(NSString*) convertToFractions:(float *)float2 aString:(NSMutableString *) myString;
And make sure you return an NSString before reaching the end of the method with
return MyNSStringVariable;
[EDIT]
I can see you are hoping that outputFraction will be returned by your method but that is not the case with Objective-C (not sure about Pascal). You are simply passing outputFraction as a second variable in your method.
So the "right" way of doing it would be to have a method
-(NSString*)convertToFraction:(float*)float2 {
...// Do your float to fraction calculation here
...// Make sure fraction is formatted as NSString
return YourFractionVariable;
}
Then you can assign the return value to a variable of your choice, for instance:
NSString *fraction = [self converToFraction:aFloatNumber];
NSLog (#"fraction is %#", fraction);
Cheers,
Rog
Why not just return the string?
- (NSString*)convertToFractions:(float)float {
//Bla bla do everything
return [myString autorelease]; //Autorelease is for memory-management
}
Btw: You seriously need to read into ObjC. Please don't try to use your old pascal-knowledge on ObjC. It's different, and your knowledge isn't really applicable.
I would recommend buying a book about ObjC or reading some good tutorials for it. (Apple itself has some very good ones)
If you don't want to return NSString from your method as others suggested you can pass a pointer to NSString pointer to your function (the same way you pass NSError** to some standard api callsm e.g. in NSFileManager methods). Your code will look something like:
NSString *outputFraction;
[self convertToFractions:&float1 aString:&outputFraction];
-(void) convertToFractions:(float *)float2 aString:(NSMutableString **) myString{
...
if (myString)
*myString = [NSString stringWithString:[[decimalInchArray objectAtIndex:x]objectAtIndex:1]];
}

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.