Why is NSArray mutable when used from Swift? - objective-c

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.

Related

Do Swift arrays retain their elements?

I'm porting one part of my objective-c framework where I had my custom MyNotificationCenter class for observing purposes.
The class had a property of type NSArray with all observables which are interested in notifications.
In objective-c, an array retains its elements, and that is unneeded because observer may not exist anymore at the point when center tries to notify him, and you don't want to have retain cycle.
Therefore I was using this block of code which kept all the items in the array without retaining them:
_observers = CFBridgingRelease(CFArrayCreateMutable(NULL, 0, NULL));
I know Swift is a different beast, however is there such concept in Swift?
Yes, an Array object in Swift retains its elements.
From the Apple Documentation:
Swift’s Array type is bridged to Foundation’s NSArray class.
so it has the same behavior of NSArray.
Reading your ObjectiveC code, what you want to achieve is to have an NSArray-like class that doesn't retain elements. This can be also achieved in another way using NSHashTable:
NSHashTable *array = [NSHashTable weakObjectsHashTable];
The NSHashTable has almost the same interface as the normal NSSet (NSHashTable is modeled after NSSet), so you should be able to replace your NSArray value with NSHashTable value with small changes.
Yes, Swift arrays do retain their elements
Let's define a simple class
class Foo {
init() {
print("Hello!")
}
deinit {
print("Goodbye...")
}
}
And now let's try this code
var list = [Foo()]
print(1)
list.removeAll()
This is the output
Hello!
1
Goodbye...
As you can see the Foo object is retained in memory until it is removed from the array.
Possible solution in Swift
You could create your own WeakArray struct in Swift where each element is wrapped into a class with a weak reference to the element. The class object is then inserted into the array.

pointer pointer in objective-c

In c++ i would do the following,
Object* obj1;
Object* obj2;
Object** targetObj;
void SetTargetToObj1()
{
targetObj = &obj1;
}
void SetTargetToObj2()
{
targetObj = &obj2;
}
void ValueChanged()
{
//So if SetTargetToObj2() was called before ValueChanged() we
// would be changing some data on obj2
(*targetObj)->ChangeSomeData();
//or, we obj2 is null we could assign a new object to it via targetObj
(*targetObject) = new Object();
//now obj2 is pointing to our new object
}
Im wondering if there is a way in obj-c to do this same thing with NSObjects?
Pointers to pointers are not so simple under ARC.
When you declare, say, an instance variable:
NSObject *someObject;
you are implicitly declaring:
NSObject * __strong someObject;
i.e. a strong pointer. Strong is just one of the ownership qualifiers, you can also have weak and autoreleasing qualifiers.
Now taking the example in your comment:
NSDate **targetDate;
you get the error "pointer to non-const type 'NSDate *' with no explicit ownership". This is because ARC needs to know the ownership qualification of the pointer your pointer is referring to (read it slowly! ;-)). i.e ARC is asking you to type the variable instead as:
NSData * 'some ownership qualifer' * targetDate;
which, once you've decoded C's type priority rules, is a "pointer to a 'some ownership qualifier' pointer to an NSDate".
The error message includes "non-const" as this is all about writing via your pointer to pointer - ARC still needs to know how to handle the store, which depends on whether the pointed at reference is strong, weak, etc.
In your simple case the following should do:
NSObject *obj1;
NSObject *obj2;
NSObject * __strong * targetObj;
and then when doing (*targetObj) = ... etc. ARC knows what to do for memory management - which in this case is to release the old value in the variable referenced by targetObj as well as assigning the new reference into that variable.
Essential reading is Automatic Reference Counting and Transitioning to ARC Release Notes - in particular look up NSError in the latter as it explains how the common pattern of declaring error parameters as NSError ** is handled under ARC.
The code you have right there is already fine. If Object is in fact an obj-c object then this exact code is what you want. The only quirk is potential memory management issues (e.g. does targetObj need to retain the thing it's pointing to?)

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;
}

Objective-C pattern for class instance variables?

What would be a nice pattern in Objective-C for class variables that can be "overridden" by subclasses?
Regular Class variables are usually simulated in Objective-C using a file-local static variables together with exposed accessors defined as Class methods.
However, this, as any Class variables, means the value is shared between the class and all its subclasses. Sometimes, it's interesting for the subclass to change the value for itself only. This is typically the case when Class variables are used for configuration.
Here is an example: in some iOS App, I have many objects of a given common abstract superclass (Annotation) that come in a number of concrete variations (subclasses). All annotations are represented graphically with a label, and the label color must reflect the specific kind (subclass) of its annotation. So all Foo annotations must have a green label, and all Bar annotations must have a blue label. Storing the label color in each instance would be wasteful (and in reality, perhaps impossible as I have many objects, and actual configuration data - common to each instance - is far larger than a single color).
At runtime, the user could decide that all Foo annotations now will have a red label. And so on.
Since in Objective-C, Classes are actual objects, this calls for storing the Foo label color in the Foo class object. But is that even possible? What would be a good pattern for this kind of things? Of course, it's possible to define some sort of global dictionary mapping the class to its configuration value, but that would be kind of ugly.
Of course, it's possible to define some sort of global dictionary mapping the class to its configuration value, but that would be kind of ugly.
Why do you think this would be ugly? It is a very simple approach since you can use [self className] as the key in the dictionary. It is also easy to make it persistent since you can simply store the dictionary in NSUserDefaults (as long as it contains only property-list objects). You could also have each class default to its superclass's values by calling the superclass method until you find a class with a value.
+ (id)classConfigurationForKey:(NSString *)key {
if(_configurationDict == nil) [self loadConfigurations]; // Gets stored values
Class c = [self class];
id value = nil;
while(value == nil) {
NSDictionary *classConfig = [_configurationDict objectForKey:[c className]];
if(classConfig) {
value = [classConfig objectForKey:key];
}
c = [c superclass];
}
return value;
}
+ (void)setClassConfiguration:(id)value forKey:(NSString *)key {
if(_configurationDict == nil) [self loadConfigurations]; // Gets stored values
NSMutableDictionary *classConfig = [_configurationDict objectForKey:[self className]];
if(classConfig == nil) {
classConfig = [NSMutableDictionary dictionary];
[_configurationDict setObject:classConfig forKey:[self className]];
}
[classConfig setObject:value forKey:key];
}
This implementation provides no checking to make sure you don't go over the top superclass, so you will need to ensure that there is a value for that class to avoid an infinite loop.
If you want to store objects which can't be stored in a property list, you can use a method to convert back and forth when you access the dictionary. Here is an example for accessing the labelColor property, which is a UIColor object.
+ (UIColor *)classLabelColor {
NSData *data = [self classConfigurationForKey:#"labelColor"];
return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
+ (void)setClassLabelColor:(UIColor *)color {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:color];
[self setClassConfiguration:data forKey:#"labelColor"];
}
my answer here may help:
What is the recommended method of styling an iOS app?
in that case, your annotation just holds a reference to a style (e.g. you need only one per style), and the size of a pointer for an entire style is not bad. either way, that post may give you some ideas.
Update
Jean-Denis Muys: That addresses the sample use case of my question, but not my question itself (a pattern to simulate class instance variables).
you're right, i didn't know how closely your example modeled your problem and i considered commenting on that.
for a more general and reusable solution, i'd probably just write a threadsafe global dictionary if your global data is nontrivial (as you mentioned in your OP). you could either populate it in +initialize or lazily by introducing a class method. then you could add a few categories to NSObject to access and mutate the static data -- do this for syntactical ease.
i suppose the good thing about that approach is that you can reuse it in any program (even though it may appear ugly or complex to write). if that's too much locking, then you may want to divide dictionaries by prefixes or create a simple thread safe dictionary which your class holds a reference to -- you can then synthesize an instance variable via the objc runtime to store it and declare an instance method to access it. the class method would still have to use the global data interface directly.

Is it best to return NSArray or void and update self property?

I am working on a delegate class that controls several views, and find myself switching between updating properties in the delegate and returning values from methods. What is the proper way to do this?
-(NSArray)blah{
return myarray;
}
or
-(void)blah{
[self myarray:value]
}
--------------- Clarification of question below
if I have a helper method that converts an NSArray into a NSDictionary
should I call my helper method and expect a return of NSDictionary, or should I update a variable in memory and return void.
There's a case for each approach, depending on what you are really doing. The two choices are:
It is truly a helper method, that has use in many places in your application.
It is specific to a single class and the dictionary is a member of that class.
OPTION 1) If it is truly a helper method, I believe that you should return the NSDictionary from the method. I'm assuming it is newly allocated within that method.
In other words, prefer:
+ (NSDictionary *) dictFromArray:(NSArray *);
If it has utility outside of a single class, you could put it in a sensible class that collects related utility methods.
The alternative approach of passing in an empty dictionary to be filled is practiced in C because it creates symmetry around allocating and freeing and makes it clear who owns the memory.
In Objective-C, reference counting takes care of that, so you can avoid the extra code of allocating empty objects just to call the method.
For example:
NSMutableDictionary *myDict = [[NSMutableDictionary alloc] init];
dictFromArray(myArray, myDict);
When it comes to knowing who owns the object, you should stick to Objective-C conventions, where:
+ (NSDictionary *) dictFromArray:(NSArray *)array
returns an autorelease object, so the caller knows they need to retain it if they want to hold a reference.
OPTION 2) If the functionality is specific to a single class and that class has the dictionary as a member, then I would pass in the array, update the dictionary member variable using the array contents, and return void.
Something like:
- (void) setBlahFromArray:(NSArray *)array
The question is confusing as stated. If they are properties then you have accessor methods that usually include something like:
-(void) setMyValue: (NSString*) inNewValue;
-(NSString*) myValue;
but it seems like you are probably asking something else since these can be dynamically synthesized for you by the compiler... So try rephrasing the question and we'll try again to help.