newbie objective c pointer question "*" syntax - objective-c

I'm often getting warnings about passing the wrong pointer types to functions and I just want to once and for all understand this properly.
What is the difference between these two?
CFURLRef *ref=(CFURLRef *)sourceURLArray[0];
CFURLRef ref=(CFURLRef )sourceURLArray[0];
Does the first one actually reference the memory address of the object in the array?
Does the second one make a copy of it?
The main style of code that I'm pursuing at the moment is to have an array of values or objects. I want to be able to use these values, passing them to other functions, without altering the originals.
Leading from that the 2 function declarations I have been trying are the following.
- (void) loadAudioFileIntoMemory:(CFURLRef *)address channel:(int) value row:(int) value2;
- (void) loadAudioFileIntoMemory:(CFURLRef )address channel:(int) value row:(int) value2;
What would the difference be?

CFURLRef is already a pointer -- it's declared as:
typedef const struct __CFURL *CFURLRef;
In general, you will want to use the type CFURLRef without the * when declaring a variable to hold a URL. Most (or all?) of the Core Foundation objects are defined this way, and you can assume a type that ends in Ref is a pointer.
So if you want an array of 10 URLs, you would write something like:
CFURLRef sourceURLArray[10];
//... populate the array.
// Get a particular URL out of the array:
CFURLRef ref = sourceURLArray[0];
What maybe makes this slightly confusing is that the Objective-C counterpart, NSURL, does need a * to make it a pointer as with all Cocoa objects. So you'd write something like:
NSURL *sourceURLArray[10];
...
NSURL *url = sourceURLArray[0];
Finally, you might find it easier to use an NSArray of NSURL objects than using plain C arrays:
NSArray *sourceURLs = [NSArray arrayWithObjects:...];
NSURL *url = [sourceURLs objectAtIndex:0];

Related

stringByAppendingString on same object

i want to ask a question on NSString, the question is if
NSString str = #"Hello";
str = [str stringByAppendingString:#"World"];
if we NSLog the str we would get an output - HelloWorld!
So my question is if str is NSString class variable an its an static one (which can not be changed once it is defined) then how can we able to change it, (Note that I have used same NSString object str).
You haven't declared the string as static, but NSString is immutable. You are creating a new string and replacing str. Many Obj-C classes have a mutable type, so if you intended to modify your string as in this example, you might want something more like:
NSMutableString *str = [NSMutableString stringWithString:#"Hello"];
[str appendString:#" World"];
Note, #"Hello" is a NSString, so attempting to initialize a NSMutableString using that syntax would result in an error.
Actually, static variables can be changed once they are defined. Static variables are simply maintained throughout all function/instance calls. You can find a more detailed explanation here static variables in Objective-C - what do they do?. So the result would be the same. If the variable were defined as const (which cannot be changed) then you would get a compiler error. Generally speaking, the best way to figure these types of things out is to just try them on your own. If it's just a matter of writing a couple lines of code, or changing a keyword, what does it hurt?

Objective-C: Is there any trick to avoid casting of NSArray objects?

Very often I find myself casting objects in NSArray to my types, when I want to access their specific properties with dot notation (instead of getter) without creating an extra variable.
Is there any cool feature or trick to tell objective-c which one class of objects I'm going to store to NSArray, so that compiler will assume objects in an array to be my type, not an id?
If you mean you're doing things like:
x = ((MyClass *)[myArray objectAtIndex:2]).property1;
You can just split it into two lines to be easier to read:
MyClass *myObject = [myArray objectAtIndex:2]
x = myObject.property1;
If you're really set on the first case, you could make a category on NSArray that has an accessor for your type:
#implementation NSArray (MyCategory)
- (MyClass *)myClassObjectAtIndex:(NSUInteger)index
{
return [self objectAtIndex:index];
}
#end
And then you can use it like you want:
x = [myArray myClassObjectAtIndex:2].property1;
Don't use properties in this situation. You can't say
arr[ix].myProperty
But you can always say
[arr[ix] myProperty]
Strictly answering to your question, no.
There's no language support for indicating the parametric type of a collection, i.e. something like NSArray<MyClass>.
That said, you can find workarounds for avoiding an explicit cast.
Since the returned object is of type id you can invoke any - existing - method on it and the compiler won't raise an eyebrow, unless you're using dot-syntax notation, which has stricter compiler checks.
So for instance
NSString * name = [people[0] firstName];
works flawlessly without a cast, whereas
NSString * name = people[0].firstName;
doesn't.

confused about NSString *str

I am kind of confused by the behavior of NSString *str..
I assigned it in several ways, sometimes it works, and sometimes it becomes null.
NSString *str = #"/hi/hello"; // this one always works
// this sometimes becomes null after the function ends
NSString *str2 = [str lastPathComponent];
// as above
NSString *str3 = [NSString stringWithString:str2];
NSString *str4 = [NSString initWithString:str3];
I am not quite familiar with the object behavior of Obj-C, is it just like C++?
If so, how can I do assignment safely like
string str = "hi";
string str2 = str;
behaves in C++?
ex: I declare a string in my .h file,
how to assign it safely that it wouldn't become NULL after a function ends?
I know it's a very basic question, but I can't find the answer in NSString reference page.
Really thanks for any help!
The behaviour is not just like C++. Objects are reference-counted. If you want to keep one around, you must place a claim on it.
If you create the object yourself with a method whose name includes the word alloc, new or copy then you have ownership already. This is like a C++ new. (When you have created an object with alloc, you need also to initialise it with some method whose name begins init. But you have to create it first. In C++ both things would be considered parts of the single act of construction.)
Objects you receive from other methods (such as two of the three NSString methods you mention) are only transiently available unless you explicitly claim ownership by calling [object retain]. You only need to do this if you want to keep them around beyond the immediate context. (There isn't really an equivalent to this in C++.)
However you gain ownership, you must relinquish it when you are finished by calling [object release]. This sort of like a C++ delete, except that the object isn't actually destroyed until all ownership claims are released.
Getting to grips with this is really really really important, perhaps the only important thing you need to know to use Objective-C. Read the object ownership documentation carefully and you'll be sorted.
I assume you're not using garbage collection? If this is the case then you need to retain the string.
NSString* str2 = [[str lastPathComponent] retain];
I suggest you do some reading on objective-c memory management.
NSString *str = #"/hi/hello";
This works because it creates a string literal. Answers to this question are worth a read to understand these in Objective-C
What's the difference between a string constant and a string literal?
In all these cases you are creating autoreleased strings. These will be deallocated when you return to the application's runloop.
NSString *str2 = [str lastPathComponent];
NSString *str3 = [NSString stringWithString:str2];
In this last one I assume you meant [[NSString alloc] initWithString:str3]
This creates a string that is retained. But this isn't a good way to create static strings.
You should create static strings in your implementation file like this
static NSString *myConstant = #"constantString"

How to use #encode() to get #"NSArray" in Objective-C

I'm using the runtime functions to get the type of a property (thanks to eJames for helping me to figure out this way).
The attribute string of the property looks like this:
T#"NSArray",&,Vstuff
I need to check if the property type is an array, at the moment I'm doing it like this:
- (BOOL)valueForKeyIsArray:(NSString *)key fromTagret:(id)target
{
NSString *lowerCaseKey = [self convertToKVCKey:key];
objc_property_t property = class_getProperty([target class], [lowerCaseKey UTF8String]);
NSString *propertyAttrs = [NSString stringWithUTF8String:property_getAttributes(property)];
NSString *encodedType = #"#\"NSArray\"";
NSRange range = [propertyAttrs rangeOfString:encodedType options:NSLiteralSearch];
return range.location != NSNotFound;
}
But since Apple can change the type definition string at any time, I would like to generate this #"NSArray" type string. I tried it with #encode(), but it did not work:
NSString *encodedType = [NSString stringWithUTF8String:#encode(NSArray *)];
So how can I generate this type string? Or is there a better way to check if this property attributes contain the array type?
There is no way to check this. In Objective-C source code the variables being typed as NSArray * is only there for the compiler to issue warnings. It has no meaning, and does not exist at runtime. If you mis-typed an NSArray as an NSString, you would get lots of warnings when compiling, but your code would behave exactly the same when run. At runtime all that is known is that the ivar/property is "an object".
Another way to think of it, is that once Objective-C is compiled, all object references are id references.
Just accept that if the runtime changes, your code will break, and move on. However, I think you might be miscategorizing ivars of type NSMutableArray *, CFArrayRef, or CFMutableArrayRef. You also seem to be assuming all keys correspond directly to a declared property.
The cleanest solution might be to assert that the sample object being used for the test (the target) must have a non-nil value for that key, and just grab the value and test that [[target valueForKey:key] isKindOfClass:[NSArray 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.