Constants/Variable AND Non-Mutable/Mutable - objective-c

Today one of my student asked me what is the technical difference between these two concepts
Constant and Variable
Non Mutable and Mutable
because we know Constants are Non Mutable and Variables are Mutable.
I told him that Mutable/Non Mutable is concept of Cocoa Framework and Constants/Variable is not. But i am not sure i was right
I know its usage but didn't find any proper technical answer.

You are right about constants being non-mutable and variables being mutable.
The mutable vs non-mutable in the cocoa framework are often ties to data structures (such as arrays, queues, dictionaries, etc).
Where mutable means we can alter the data structure (add/remove objects) and immutable means we can't modify it (just read).
Hope this helps

Constness in Objective-C referes to object references, but never to objects (as i. e. in C++). Mutability refers to objects.
// non-const reference to immutable string object
NSString *s = …;
// You can change the reference, …
s = …; // No error
// … but not the string object
[s appendString:…]; // Error
// const reference to immutable string object
const NSString* s = …;
// You can neither change the reference, …
s = …; // Error
// … nor the string object
[s appendString:…]; // Error
// non-const reference to mutable string object
NSMutableString *s = …;
// You can change the reference …
s = …; // No Error
// … and the string object
[s appendString:…]; // No error
// const reference to mutable string object
const NSMutableString *s = …;
// You cannot change the reference, …
s = …; // Error
// … but the string object
[s appendString:…];
So you can say that immutability is the "constness of (OOP) objects".
However constness of "variables" (to be more precise: C objects that are no Objective-C objects) is important to the compiler for optimization, because it is SSA. Immutability is important for many things in your design.
Even for (Objective-C) objects immutability is important and not as often considered as it should be. Especcially for "data classes" that are passed around, an immutable version should be considered making things easier. This applies to your own classes, too.

Related

Why is NSArray mutable when used from Swift?

I have an objective-c header with the following property
#property (nullable, nonatomic, strong) NSArray<CustomObject *> *customObjects;
If I create a swift extension of that class I can now remove objects from the NSArray:
self.customObjects?.remove(at: 0)
Also if I do
print(type(of: self.customObjects))
I get:
Array<CustomObject>
Aren't NSArrays immutable ? Does Swift create a shallow copy whenever we edit it?
Your property is (implicitly) declared readwrite in ObjC. This means you can change the property writing a new NSArray instance that replaces the old (in which case the new instance's constants might be derived by first reading the other NSArray instance that's the existing value of the property):
NSArray *currentObjects = self.customObjects;
// one of many ways to derive one immutable array from another:
NSArray *newArray = [currentObjects subarrayWithRange:NSMakeRange(1, currentObjects.count - 1)];
self.customObjects = newArray;
In Swift, your property comes across as a Swift.Array (that is, the Array type from the Swift standard library), which is a value type. Every assignment semantically creates a copy. (The expensive work of performing the copy can be deferred, using a "copy on write" pattern. Arrays of reference types, like objects, copy references instead of storage, so it's essentially a "shallow copy".)
Mutating operations do this, too:
let currentObjects1 = self.customObjects
currentObjects1.remove(0) // compile error
// currentObjects1 is a `let` constant so you can't mutate it
var currentObjects = self.customObjects
currentObjects.remove(0) // ok
print(self.customObjects.count - currentObjects.count)
// this is 1, because currentObjects is a copy of customObjects
// we mutated the former but not the latter so their count is different
self.customObjects = currentObjects
// now we've replaced the original with the mutated copy just as in the ObjC example
When you have a readwrite property in Swift, and the type of that property is a value type like Array (or is an ObjC type that's bridged to a value type, like NSArray), you can use mutating methods directly on the property. That's because calling a mutating method is semantically equivalent to reading (and copying) the existing value, mutating the copy, and then writing back the changed copy.
// all equivalent
self.customObjects.remove(0)
self.customObjects = self.customObjects.dropFirst(1)
var objects = self.customObjects; objects.remove(0); self.customObjects = objects
BTW: If you're designing the API for the ObjC class in question here, you might consider making your customObjects property nonnull — unless there's a meaningful semantic difference between an empty array and a missing array, your Swift clients will find it cumbersome needing to distinguish the two.

NSFastEnumeration object casting in ARC

I'm trying to implement the countByEnumeratingWithState:objects:count: method from the NSFastEnumeration protocol on a custom class.
So far I have it iterating through my objects correctly, but the objects that are returned aren't Objective-C objects but rather the core foundation equivalents.
Here's the part of the code that sets the state->itemsPtr:
MyCustomCollection.m
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState *)state
objects: (id __unsafe_unretained *)buffer
count: (NSUInteger)bufferSize {
// ... skip details ...
NSLog(#"Object inside method: %#", someObject);
state->itemsPtr = (__unsafe_unretained id *)(__bridge void *)someObject;
// ... skip details ...
}
Then I call the 'for..in' loop somewhere else on like this
SomeOtherClass.m
MyCustomCollection *myCustomCollection = [MyCustomCollection new];
[myCustomCollection addObject:#"foo"];
for (id object in myCustomCollection) {
NSLog(#"Object in loop: %#", object);
}
The console output is:
Object inside method: foo
Object in loop: __NSCFConstantString
As you can see, inside the NSFastEnumeration protocol method the object prints fine, but as soon as it gets cast to id __unsafe_unretained * I lose the original Objective-C corresponding class.
To be honest I'm not quite sure how the (__unsafe_unretained id *)(__bridge void *) casting works in this case. The (__unsafe_unretained id *) seems to cast to match the right type itemsPtr needs. The (__bridge void *) seems to cast to a pointer of type void with __bridge used to bridge the obj-c world to the CF world. As per the llvm docs, for __bridge:
There is no transfer of ownership, and ARC inserts no retain operations
Is that correct?
From my understanding __NSCFConstantString is just the core foundation equivalent of NSString. I also understand that with ARC you need to bridge from Objective-C objects to CoreFoundation equivalents because ARC doesn't know how to manage the memory of the latter.
How can I get this working so that the objects in my 'for..in' loop are of the original type?
Also note that in this case I'm adding NSStrings to my collection but in theory it should support any object.
UPDATE
Rob's answer is on the right track, but to test that theory I changed the for loop to this:
for (id object in myCustomCollection) {
NSString *stringObject = (NSString *)object;
NSLog(#"String %# length: %d", stringObject, [stringObject length]);
}
In theory that should work since the objects are equivalent but it crashes with this error:
+[__NSCFConstantString length]: unrecognized selector sent to class
It almost looks like the objects returned in the for loop are classes and not instances. Something else might be wrong here... Any thoughts on this?
UPDATE 2 : SOLUTION
It's as simple as this: (thanks to CodaFi
state->itemsPtr = &someObject;
You're incorrectly casting someObject. What you meant is:
state->itemsPtr = (__unsafe_unretained id *)(__bridge void *)&someObject;
(Let's get rid of those awful casts as well)
state->itemsPtr = &someObject;
Without the address-of, your variable is shoved into the first pointer, which is dereferenced in the loop. When it's dereferenced (basically, *id), you get the underlying objc_object's isa class pointer rather than an object. That's why the debugger prints the string's value inside the enumerator call, and the class of the object inside the loop, and why sending a message to the resulting pointer throws an exception.
Your code is fine the way it is. Your debug output is revealing an implementation detail.
NSString is toll-free-bridged with CFString. This means that you can treat any NSString as a CFString, or vice versa, simply by casting the pointer to the other type.
In fact, under the hood, compile-time constant strings are instances of the type __NSCFConstantString, which is what you're seeing.
If you put #"hello" in your source code, the compiler treats it as a NSString * and compiles it into an instance of __NSCFConstantString.
If you put CFSTR("hello") in your source code, the compiler treats it as a CFStringRef and compiles it into an instance of __NSCFConstantString.
At run-time, there is no difference between these objects in memory, even though you used different syntax to create them in your source code.

What does the const specifier do, before a pointer to object?

If I have a C-string like this:
const char* str= "hello";
I know well that I can't change any character of the string because the pointer is const.
But if I have this:
- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location
I can still mutate the object state using it's methods.
If the pointer is to a NSMutableString, I'm still able to mutate it.
Then what does the const stand for?
In that method declaration, location is a pointer to a constant CLLocation. But when you send a message to the location object, the const-ness is not preserved; the method that handles the message sees self as a non-const object. (Note that this is different than C++, which supports const member functions where this is a pointer to a constant object.)
So the const in that declaration is not particularly useful. Perhaps it was written by someone used to the C++ way of doing things.
When you do see const attached to an object pointer in Objective-C, it is usually like this:
extern NSString * const SomeConstantString;
This declares SomeConstantString as a constant pointer to some non-constant object (in this case, an NSString). The pointer itself is constant, so your program can't change SomeConstantString to point to some other NSString object.
I know well that I can't change any character of the string because
the pointer is const.
No, the pointer is mutable. The characters it points to are const.
I can still mutate the object state using it's methods.
There is no const-correctness for Objective-C objects like there is in C++. The compiler does not care which messages (mutating or not) you send to a const object. So there's no sense in declaring a pointer to a const object. The cited framework method is an anomaly, probably an oversight.
Mind the difference:
// constant pointer
char * const str = "";
// pointer to constant (two equivalent ways)
const char * str = "";
char const * str = "";
The keyword const applies applies to whatever is immediately to its left. If there is nothing to its left, it applies to whatever is immediately to its right.
In Objective-C all method parameters are always passed by value. This includes primitives, structs, unions, and pointers, and any other made up type.
Note that you can't have variables of type object. A expression like NSObject o; produces a compiler error with message "Interface type cannot be statically allocated".
The only way to pass an object is passing a pointer. The pointer is passed as value, but lets the code inside the method reference the object and change it. So in a way, it is as if you are passing the object by reference (in reality you are passing the pointer by value).
When compiling an Objective-C program, the methods are turned into C functions, and each "message send" (aka "method call", though it isn't exactly the same) is ran using the runtime function objc_sendMsg. This function doesn't know or care if you qualified the object with const or not. If you want an immutable object, you have to code that immutability inside the object. Example:
// const qualifying an object is ignored whether in variables or method arguments:
const NSMutableArray *array = [NSMutableArray new]; // const is ignored
-(void)someMethod:(const NSMutableArray *)array { ... // const is ignored
// calling the methods that mutate the object works fine
[array removeAllObjects];

Is there any way to specify the class of objects of a NSMutableArray?

Im having the following problem:
I've made a NSMutableArray "array" that is going to contain objects of a class named "Class". At the start that array should be empty and it must be filled during the program's execution.
As I never actually told the compiler that my NSMutableArray will be holding elements of the class Class, when I try to write the appropriate methods the compiler wont let me do it.
This is my first experience on Objective-C and iPhone development. I used to code in C/C++ where I declared my arrays in the following way:
Class array[NUMBEROFELEMENTS];
Is there any way to do this in Objective-C?
Thanks!
The truth is that is doesn't matter to the NSMutableArray what type of object it is. NSMutableArray simply stores pointers to all the objects they contain, or reference.
The trick is when you pull the object back out of the array you need to create a new pointer based on the appropriate type:
MyObject *myObject = [myArray objectAtIndex:0];
Then you can use the object however you like:
[myObject doThatThingWithThisValue:10];
Or whatever you need.
Arrays in Objective-C Cocoa are objects (as well as other collections, sets, dictionaries). Arrays can contain references to objects of any type, so the type for the array is simply NSArray, NSMutableArray, etc...
Since they are objects, you can send them messages to manipulate their content.
I suggest you take a look at Apple's excellent Collections Programming Topics, which explain the rudiments of collections.
Here is a quick example :
// two objects of different types
NSNumber *n = [NSNumber numberWithInteger:10];
NSString *s = #"foo";
// alloc/init a new mutable array
NSMutableArray *a = [NSMutableArray arrayWithCapacity:10];
// add an object
[a addObject:n];
[a addObject:s];
// array a now contains a NSNumber and a NSString
Well, you can still have C-style arrays in Objective-C.
However, the characteristics of Objective-C (some people will call it strength, other will call it weakness) is that it has dynamic typing of objects and dynamic dispatch.
It has NSArray and NSMutableArray which are not specialized for the certain class. It can store objects of non-compatible classes.
You can use the following idiom: [obj isMemberOfClass: [Class type]] to make sure an array element is of the desired type and then cast to Class*.
You can also use for-each loop (aka Fast Enumeration):
NSMutableArray* array = //... initialize your array
for (Class* elm in array) {
elm.your_property = 10;
}

Why does NSString respond to appendString?

I was playing with the respondsToSelector method in Objective-C on MacOS-X 10.6.7 and Xcode 4.0.2, to identify if an object would respond to certain messages. According to the manuals, NSString should not respond to appendString: while NSMutableString should. Here's the piece of code which tests it:
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *myString = [[NSString alloc] init];
if ([myString respondsToSelector:#selector(appendString:)]) {
NSLog(#"myString responds to appendString:");
} else {
NSLog(#"myString doesn't respond to appendString:");
}
// do stuff with myString
[myString release];
[pool drain];
return 0;
}
and here's the output:
Class02[10241:903] myString responds to appendString:
I'd sort of expected the opposite. How does an NSString object respond to appendString: ? What's going on here that I'm missing ?
Short answer: That string is of type NSCFString, a class that inherits from NSMutableString, hence it responds to the selectors for the methods declared in NSMutableString, including superclasses.
Not so short answer: Foundation strings are toll-free bridged with Core Foundation strings. Developers use the opaque types CFStringRef (bridged with NSString) and CFMutableStringRef (bridged with NSMutableString) to refer to these strings so, at first glance, there are two different types of strings: immutable and mutable.
From a Core Foundation internal implementation perspective, there’s a private type called struct __CFString. This private type keeps a bit field that stores, amongst other information, whether the string is mutable or immutable. Having a single type simplifies implementation since many functions are shared by both immutable and mutable strings.
Whenever a Core Foundation function that operates on mutable strings is called, it first reads that bit field and checks whether the string is mutable or immutable. If the argument is supposed to be a mutable string but it in fact isn’t, the function returns an error (e.g. _CFStringErrNotMutable) or fails an assertion (e.g. __CFAssertIsStringAndMutable(cf)).
At any rate, these are implementation details, and they might change in the future. The fact that NSString doesn’t declare -appendString: doesn’t mean that every NSString instance doesn’t respond to the corresponding selector — think substitutability. The same situation applies to other mutable/immutable classes such as NSArray and NSMutableArray. From the developer perspective, the important thing is that the object that’s been returned is of a type that matches the return type — it could be the type itself or any subtype of that type. Class clusters make this a tad more convoluted but the situation is not restricted to class clusters per se.
In summary, you can only expect that a method returns an object whose type belongs to the hierarchy (i.e., either the type itself or a subtype) of the type for the return value. Unfortunately, this means that you cannot check whether a Foundation object is mutable or not. But then again, do you really need this check?
You can use the CFShowStr() function to get information from a string. In the example in your question, add
CFShowStr((CFStringRef)myString);
You should get an output similar to:
Length 0
IsEightBit 1
HasLengthByte 0
HasNullByte 1
InlineContents 0
Allocator SystemDefault
Mutable 0
Contents 0x0
where
Mutable 0
means that the string is in fact immutable.
This probably has to do with the implementation. NSString is a class cluster, which means that NSString is just a public interface and the actual implementing class is different (see what the class message gives you).
And at the same time NSString is also toll-free bridged to CFString, meaning that you can switch before those two types freely just by casting:
NSString *one = #"foo";
CFStringRef two = (CFStringRef)one; // valid cast
When you create a new string you really get a NSCFString back, a thin wrapper around CFString. And the point is that when you create a new mutable string, you also get an instance of NSCFString.
Class one = [[NSString string] class]; // NSCFString
Class two = [[NSMutableString string] class]; // NSCFString
I guess this was convenient from the implementation point of view – both NSString and NSMutableString can be backed by a common class (= less code duplication) and this class makes sure you don’t violate the immutability:
// “Attempt to mutate immutable object with appendString:”
[[NSString string] appendString:#"foo"];
There’s a lot of guess work in this answer and I don’t really understand the stuff, let’s hope somebody knows better.
You should not make assumptions about a method being not there. That method might be used internally or for whatever reason it exists. Technically, it's just private API.
You only have a contract to the public declarations (docs), and they don't show that message. So be prepared to get into trouble rather quickly if you use other features.