I am close to pulling my hair out on this. I have the need to create a type of object such that when a new object is instantiated it associates itself with every other object of that class via an array property. That is object1 gets created and has an array with no other objects. Object 2 gets created and has an array with object1. Object 3 gets created and has an array with object1 and object2. Also object1 and object2 now have object 3 in their arrays.
This has proved more difficult that I had prejudged by simply using conditional logic and for-in looping.
I have attempted to create an object manager class to keep a list of all objects created and use those references to loop through its owned objects and "cross-pollinate" them with each other. Check for ![object1.name isEqualToStringName:thisObject.name] in each for-in loop.
I imagine this may be somewhat opaque and needlessly confusing to some. The essence of what I want to do is dynamically associate every object with every object via an array property.
The app creates object8 and object8 is added to the arrays of object1...object7.
This is something I am attempting to do in a larger context of an app where the objects must maintain situational awareness of each other and having an array of each other will help to facilitate that. If there is a design pattern, methodology, principle or something I am missing here please.. please inform me.
Related
I understand that normally you use copy for NSStrings, so that your property stays as the same value as when you assigned it, even when there's an attempt to re-set it somewhere else.
But I am having hard time completely understanding this concept. Doesn't this apply to basically any kind of object (not just NSStrings)?
So my question is, "What kind of properties should I set as 'copy', and why?"
Objects that are simple bits of data, like strings, that won't have references to a ton of other objects in your application are great for copying.
Now you can, of course, retain things like strings instead. This will work fine. But what if you had a mutable string instead, and you modified it. Now every other object that had a reference to that string will see that modification. This may not be what you want. This is one reason copying is "simpler", because any changes to that data is localized to just that bit of code.
On the other hand, lets say you have a instance of a class you wrote for your app. It has references to other objects in your app, it has a ton of it's own strings or other values in it, and it's a complex beast. Now copying this object may not be a good idea. Chances are that if you modify this object then you want the changes to propogate to every object that holds a reference. And even if you did copy it, do you need a shallow copy (a new instance but it's ivars references the same objects) or a deep copy (a new instance containing containing new copies of every ivar)? And the object in question may not even support <NSCopying>, meaning it can't technically be copied at all.
So to sum up:
copy: Objects that are small, atomic bits of data without any internal references to other objects.
retain: Nearly every other kind of object.
Client code can assign an NSMutableString object to an NSString property. If the property was defined as strong or some other non-copy attribute, then if the client later changes the mutable string, the property's value would now be different. By setting the property to be 'copy', a copy of the string value is made and this ensures the value can't change behind your back.
So basically you should use copy whenever the property is for a type that has a mutable counterpart and you want to ensure the value doesn't change on you.
Let's say variable A and B hold instances of managed objects in the same managed object context. I need to make sure that they are associated with the same "record" in the persistent store. The section on Faulting and Uniquing in the Core Data Programming Guide says that:
Core Data ensures that—in a given managed object context—an entry in a persistent store is associated with only one managed object.
From this, it seems that a pointer comparison is sufficient for my purpose. Or does it ever make sense to use isEqual: to compare managed objects in the same context?
Use == to determine if two pointers point to the same object. Use -isEqual to determine if two objects are "equal", where the notion of equality depends on the objects being compared. -isEqual: normally compares the values returned by the -hash method. I wrote previously that it seemed possible that -isEqual: might return true if two managed objects contain the same values. That's clearly not right. There are some caveats in the docs about making sure that the hash value for a mutable object doesn't change while it's in a collection, and that knowing whether a given object is in a collection can be difficult. It seems certain that the hash for a managed object doesn't depend on the data that that object contains, and much more likely that it's connected to something immutable about the object; the object's -objectID value seems a likely candidate.
Given all that, I'm changing my opinion ;-). Each record is only represented once in a given context, so == is probably safe, but -isEqual: seems to better express your intention.
Pointer comparison is fine for objects retrieved from a single managed object context, the documentation on uniquing you quote promises as much.
ObjectID should be used for testing object equality across managed object contexts.
isEqual does not do attribute tests, because it is documented to not fault the object. In fact, looking at the disassembled function it is definitely just a pointer compare.
So the semantics of the equality test for managed objects are simply "points to the same object (record) in the managed object context" and will compare false for objects in different contexts.
Warning: Since NSManagedObject isEqual compares objectIDs, a comparison can fail if one instance is using the temporary objectID and the other instance is using the permanent objectID.
Background: When an NSManagedObject is created, it is assigned a temporary objectID. It is converted into a permanent objectID when the NSManagedObject is actually persisted into the store. You can see the difference if you print the objectID:
x-coredata:///MyEntity/t03BF9735-A005-4ED9-96BA-462BD65FA25F118 (temporary ID)
x-coredata://EB8922D9-DC06-4256-A21B-DFFD47D7E6DA/MyEntity/p3 (permanent ID)
When an objectID is converted to permanent, instances of the NSManagedObject in other threads and collections are not updated. So if you put an NSManagedObject into an NSArray when it has a temporary objectID, using methods like containsObject will fail if you try to find the object with the permanent objectID. Remember containsObject uses isEqual.
Finally, a couple of useful methods are NSManagedObjectID isTemporaryID and NSManagedObjectContext obtainPermanentIDsForObjects:error:.
I need some advise on the best way to achive the following:
Store a collection of a specific type of objects in order
Custom methods to search the collection
Other custom methods for returning objects from the collection based on some rules
Need instance variables to keep track of things in the collection
Originally I was thinking about sub classing the NSMutableArray class and adding the extra methods and variables that I want that are specific to the objects that I'm going to be storing in the array, but the Apple docs said this was a no no!
I know that you can use Categories but they don't support adding instance variables which I need to keep track of elements in the collection.
Also I don't want these extra methods being adding to all NSMutableArray objects just my custom one.
What is the best way to do this, the idea is to have a nice wrapper around NSMutableArray to query my custom objects and manipulate them.
Create a class (inheriting from NSObject) that contains a NSMutableArray. Write your own custom add: and remove... methods to add and remove objects from the array.
Just create a class with an NSMutableArray instance variable. Store your objects in there. Implement your methods on that class.
Suppose Object1 needs information from Object2. I'll say it's in an Object2 property, but the info could as easily be the return value from an Object2 function. When I look at others' code I see sometimes they will have a method in Object1 directly accessing the property. Other times I see people pass Object2 as a parameter in a method, and then access the property from the passed Object2.
These scenarios seem almost the same to me. Directly accessing the property seems simpler. As a newbie, what do you think I should think about when deciding how Object1 should get information from Object2? (When would I want to have an object parameter rather than directly accessing the property?)
Thanks -- Al C.
One problem with passing Object2 to Object1 is that you create a dependency between Object2 and Object1. The only way that Object1 can obtain the data it needs is to have a reference to Object2.
Now, sometimes you want that, but most of the time you don't. So you're most likely better off simply passing the value you need as a parameter to the method, rather than passing the instance of Object2.
If the method only needs the one property value from Object2, it would be best to pass that property value directly. If the method needs access to many properties or other features of Object2, passing a reference to Object2 would be appropriate.
There are exceptions - if you need to protect the signature of the method (i.e. it is public) and you foresee additional use of Object2 within the method in the future, passing the object reference may be appropriate.
The previous answers also make valid points - you should consider the coupling of Object1 and Object 2 when you make this decision.
Usually the goal is to minimize coupling between objects.
Let's use a simple example where I have three objects; an AppController, which holds a reference to a DataController and a MainWindowController. You need to pass DataController.Data to the MainWindowController, so you can display the values in a table in the main window. You could pass DataController to MainWindowController as a method parameter, or make DataController an instance variable in MainWindowController. To minimize coupling through, the cleanest way is for AppController to pass Data directly to MainWindowController, so it doesn't need to know anything about DataController.
It's all about whether or not Object1 knows about Object2. In OOP, part of good design is to have objects store as LITTLE information as possible that still allows them to behave properly. So the problem fundamentally comes down to: does Object1 need to know about Object2's existence (that is, does it need an instance of Object2 to exist) or can it be told about the existence of an Object2 instance? Usually, in OOP, you want to lean more towards the latter than the former.
However, that said, in a situation where Object1 can operate on data which comes from Object2, the best way would probably to have Object1 have a method which operates on the data type of the property on Object2; that way, you decouple Object1 and Object2, in that Object1 does not have a dependency on Object2 to provide a given property in a given way; the calling code can connect the two.
Yes, what Randolpho says is true.
Remember, with OOP you are aiming to create separate identities that can function as a whole in the system. When you start creating objects that rely heavily on each other, not only do you increase your chances of bugs, but also the chance that your program won't work anymore at all.
Now your example is a minor, but imagine 5, 10, 100 objects calling each other through parameters, that's nasty work.
Take a look at Encapsulation on wikipedia.
Encapsulation [..] protects the integrity of the component, by preventing users from setting the internal data of the component into an invalid or inconsistent state.
A question that has pondered me for the last while. I am primarily a .net developer who dabbles in Objective-C for iPhone and Mac.
How do you go about sending "datasets" between methods in objective-c. For example in C# you can populate a custom class with data and pass it around in a List of type custom class. EG if you had a customer class you would just do something like:
List<Customer> customers = DataLayer.GetAllCustomers();
The only way I can see how this could be done in obj-c would be to populate an NSArray with custom objects? Is this an efficient way to do things? Any other recommendations? I am using sqlite as the database/data I want to return.
You're on the right track.
Cocoa's collection classes — which all have mutable an immutable variants — are:
NSArray: ordered, can contain an object multiple times
NSDictionary: unordered, mapping from keys to values, keys are copied
NSSet: unordered, can contain an object only once
NSCountedSet: unordered, can contain an object multiple times
The immutable variants help a lot with efficiency. The standard pattern for accessors of classes that have mutable variants is to copy rather than retain. This is codified in the #property mechanism, by using the copy attribute on the property:
// Department.h
#interface Department : NSObject
#property (readwrite, copy) NSSet *employees;
#end
This means that if you pass a mutable array to something that takes an array, it will be copied, and if you pass that to something else, it will be copied again. The trick is though that "copying" an immutable object really just retains it, so you only take a hit for that first copy. You probably want to make a copy that first time anyway so you don't pass a mutable array to something else, then mutate it behind the back of whatever you passed it to.
For Cocoa on Mac OS X, I'd also strongly encourage you to take a look at Core Data. It's an alternative to the "data set" pattern you might be used to from .NET/ADO/etc. With Core Data, you don't "get all customers" and then pass that collection around. Instead you query for the customers you care about, and as you traverse relationships of the objects you've queried for, other objects will be pulled in for you automatically.
Core Data also gets you features like visual modeling of your entities, automatic generation of property getters & setters, fine-grained control over migration from one schema version to another, and so on.