How to set up a has-many relationship in Cocoa? - iphone

I'm building a (very) simple FTP app in Cocoa, and I need to store information on the different types of servers that are supported. So, I've created a ServerType class, which stores all of the relevant information about a single type of server. I then have a ServerTypes class which is designed to manage all of the ServerType classes that are created.
My question is, how to set up the relationship between the two objects. Is there a preferred method to do so?
Also, since Objective-C doesn't support non-instance classes, where should I create an instance of ServerTypes that will have to be used throughout the entire program? Or is there a better way to do that? I need it to be KVC compliant so That I can bind one of the ServerType properties to an NSPopupBox.
I'm fairly new to Cocoa and Objective-C.

To manage a relationship between 2 objects, you have 2 ways: composition or inheritance.
You can inherit from a class to create a subclass then you will have a is-a relationship.
If one object contains another as an instance variable then you will have a has-a relationship.
Here, I think it would be the best to use composition where the ServerTypes objects has an array of all server type objects. Objective-C supports non-instance variable (if that's what you mean), by creating static variable. Then you can use it accross the whole program

Related

Do Core Data objects replace standard class objects?

I'm getting into Core Data and have started making "Classes" out of entities. Do I use these classes based off of entities as regular classes with methods etc?
Normally if I was using SQL directly I would have classes for each of my database objects (Tables) that store the working data and perform their functions.
Is this the same with Core Data - do I use the entity-based classes (subclasses of NSManagedObject).
So I might have these entities: Business -> Departments -> Employees
To comply with Core Data - do I make one class for each of these subclassing NSManagedObject and then add methods to it accordingly (like I would an NSObject class)?
Yes, you usually use the Core Data generated classes. You usually don't add methods to those classes, instead you should put them into a Category. This is because if you change an entity, you need to regenerate the class which will erase any methods that you added.
Yes(ish). They are your model classes. You aren't creating them 'out of' entities, they are the code representation of your entities.
You should have one class per entity, but you shouldn't create them yourself. You should get Xcode to create the classes. Or, better yet, use mogenerator.

Can two inherited classes access the same variable in a base class?

What is a good way to design a class? I'm trying to create a simple chat program. I want everything the objects in the screen use to be encapsulated. I've created a few classes, a logging class, a message pile class (for holding the messages which have been received and sent), a textbox class, and a button class. I want the message pile, the textbox, and the button to share the same string variable, except I want it encapsulated within the classes.
I did try creating a Base class. This would hold all the data and functions common to the textbox and button classes. Those three classes would derive from Base to use its shared variable. Only when I did this the variable was not shared. Is there a way to do this? Kind of like a global variable? Only within its own class and its derived ones? Both objects of the two derived classes should be able to access the Base class object's variables.
You are mixing up classes and objects. When you have a base class with some member variable then all derived classes can (potentially) access the member variable in the base class.
However when you instantiate the different derived classes, or one of them multiple times, then each object has a complete independent set of member variables, including the ones from the base class, because that's exactly what an object is.
If you want certain groups of objects to use the same "shared" variables then you could stick these shared things into a dedicated "shared" class. Then for each group of objecst that need to share these "variables", you create an instance of this "shared" class, and pass it to all of the objects in the group.
This is also more flexible than fiddling around with "static" class members, or whatever they are called in the language you are using, because you can have multiple of these "groups" of objects by having multiple "shared" objects and deciding exactly which "actual" objects share the same "shared" data/variables.
Without knowing more about what's going on it's hard to give any more recommendations on how to design the class and object hierarchy.

Interface doubts

Are interfaces a layer between objects(different objects) and actions(different object types trying to perform same action)? and Interface checks what kind of object is it and how it can perform a particular action?
I'd say that it's better to think of an interface as a promise. In Java there is the interface construct that allows for inheritance of an API, but doesn't specify behavior. In general though, an interface is comprised of the methods an object presents for interacting with the object.
In duck-typed languages, if an object presents a particular set of methods (the interface) specific to a particular class, then that object is like the specifying class.
Enforcement of interface is complicated, since you need to specify some set of criteria for behavior. An interesting example would the design-by-contract ideas in Eiffel.
Are you asking about the term "interface" as used in a specific language (such as Java or Objective-C), or the generic meaning of the term?
If the latter, then an "interface" can be almost anything. Pour oil on water -- the line between them is an "interface". An interface is any point where two separate things meet and interact.
The term does not have a rigorous definition in computing, but refers to any place where two relatively distinct domains interact.
To understand interfaces in .net or Java, one must first recognize that inheritance combines two concepts:
Implementations of the derived type will include all fields (including private ones) of the base type, and can access any and all public or protected members of the base type as if it were its own.
Objects of the derived type may be freely used in place of objects of the base type.
Allowing objects to use members of more than one base type as their own is complicated. Some languages provide ways of doing so, but there can often be confusion as to which portion of which base object is being referred to, especially if one is inheriting from two classes which independently inherit from a third. Consequently, many frameworks only allow objects to inherit from one base object.
On the other hand, allowing objects to be substitutable for more than one other type of object does not create these difficulties. An object representing a database table may, for example, allow itself to be passed to a routine that wants a "thing that can enumerate contents, which are of type T (IEnumerable<T> in .net)", or a routine that wants a "thing that can have things of type T added to it" (ICollection<T> in .net), or a thing that wants a "thing that wants to know when it's no longer needed (IDisposable in .net)". Note that there are some things that want notification when they're no longer needed that do not represent enumerable collections, and there are other things that represent enumerable collections that can be abandoned without notification. Thus, neither type of object could inherit from the other, but if one uses an interface to represent "things which can enumerate their contents, which are of type T", or "things that want to know when they are no longer needed", then there's no problem having classes implement both interfaces.

What, if any, are the negative consequences of basing a Model layer on NSManagedObject?

I've been doing iOS now for about two years and mostly by consequence of simple data layers (no real need for ID's, joins, complex queries, etc), I've always managed persistence manually by extending NSObject, conforming to NSCoder, and saving my data in flat files.
However, now I am in a position where I need to start doing more complex query work and I am digging into CoreData.
My hangup right now is with NSManagedObject. It's a pretty intimidating class and I am wondering if there are any unwritten gotchas I should be aware of that might restrict my freedom while building a sophisticated application.
For example, things like #dynamic getter/setters are not to clear to me, etc
So:
1) Are there any features of NSManagedObject that would prevent me from handling instances of custom classes just as I would with NSObject?
2) Does NSManagedObject have any unusual behavior when objects are handled WITHOUT the presence of a ManagedObjectContext?
3) Can I supplant a #dynamic property declaration with my own custom getter/setter without too much pain? I use a lot of custom setters to enforce business logic.
and so on, and so on.
Thanks
Beware!
Core Data is not lightweight. It will require a lot of changes to the way your objects work, unless they are very basic.
1) Are there any features of NSManagedObject that would prevent me from handling instances of custom classes just as I would with NSObject?
Faulting and the lifecycle of managed objects are a little tricky to understand. Your objects can be "faulted" almost at any time (each iteration of the event loop anyway), which makes them lose any non-persistent state. When they get "un-faulted", they don't have access to anything outside the managed object context to restore their state. It's very hard for managed objects to access anything outside the managed object context.
Transient properties are possible, but are pretty much limited to things that can be computed from the persistent properties, since their state will be lost if the object is ever faulted. You also have to formally declare that you're using a transient property in the data model. Trying to just set up instance variables will run into problems.
So basically managed objects properties all must be persistent or related to persistent properties. Look at the objects you're planning to make managed. Are all their instance variables feasible and desirable to put into a persistent store? If not things will not be straightforward. You probably set up your instance variables in your init. There is no init that gets called every time your program runs for managed objects. There are awakeFromInsert and awakeFromFetch, but those don't work exactly like init. Your code calls init and can pass arguments. The framework calls awake and it gets no parameters.
Threading is another issue to consider. A managed object context, and therefore the managed objects in it, are recommended to be used only by a single thread. If you have multiple threads, and they need to access your model, you need to create duplicate managed object contexts containing duplicates of your managed objects. Core Data is designed to handle that without putting too much strain on memory, disk I/O, and processor, but it isn't lightweight from a coding perspective.
2) Does NSManagedObject have any unusual behavior when objects are handled WITHOUT the presence of a ManagedObjectContext?
You cannot have a managed object without a managed object context.
That's not usually an issue. Managed objects carry a pointer to their managed object context. It can be a little limiting though. If something outside your model needs to create a model object as an input to your model, it needs to have access to the managed object context to do that. Hopefully that would be through some kind of abstraction layer so it doesn't need to know it's dealing with Core Data, but you can't just give it a class and have it alloc/init. It is also a bit of work to move managed objects between different managed object contexts.
3) Can I supplant a #dynamic property declaration with my own custom getter/setter without too much pain? I use a lot of custom setters to enforce business logic.
Yes. It's a bit complicated but doable. You write your own accessors. In addition to your business logic, they must call key-value observing methods like willChangeValueForKey:. Then you access the data using primitive accessors.
1) Are there any features of NSManagedObject that would prevent me from handling instances of custom classes just as I would with NSObject?
Creating and removing them is different, but not difficult. Otherwise, no
2) Does NSManagedObject have any unusual behavior when objects are handled WITHOUT the presence of a ManagedObjectContext?
I'm not sure what you mean, you can pass a managed object to another class and use it quite happily without the other class knowing about the context, but you must have a context somewhere.
3) Can I supplant a #dynamic property declaration with my own custom getter/setter without too much pain? I use a lot of custom setters to enforce business logic.
Yes, NSManagedObject is designed for this purpose. There are plenty of examples of overridden accessors in the core data programming guide - there are some rules you need to follow but they are not too onerous.
Core data is primarily a persistence framework rather than a query framework - I imagine once you get into it you will wonder why you were wasting your time on all those NSCoding implementations...
1) Are there any features of NSManagedObject that would prevent me
from handling instances of custom classes just as I would with
NSObject?
No. You can extend a NSManagedObject subclass just like a NSObject subclass.
2) Does NSManagedObject have any unusual behavior when objects are
handled WITHOUT the presence of a ManagedObjectContext?
The #dynamic directive will create accessors optimized for saving in a persistent store managed by a context. The values will still be available just like any other object but you will generate a lot of overhead.
3) Can I supplant a #dynamic property declaration with my own custom
getter/setter without too much pain? I use a lot of custom setters to
enforce business logic.
You can but you will incur some performance penalty because the generated accessors will be highly optimized for the specific code in your app.
One major point of novice confusion with regard to managed object is missing that the generic NSManagedObject can represent any entity in the data model without subclassing. NSManagedObject has "associative storage" which basically means that it has an open dictionary attached to it that save any key-value pairs. When you you insert a generic NSManagedObject into a context, the keys of the associative storage "dictionary" are set to the property names of the entity given.
Therefore, you are actually never really forced to subclass NSManagedObject. Doing so is largely a matter of convenience.
That is why you sometimes see code that uses generic NSManagedObject and the setValue:forKey and other times you see custom subclasses that use anObject.propertyName.
I would also advise that if you find yourself using or saving managed object outside a context, then chances are good that you have a bad design.

why would I need to use a primitive accessor methods in a core data project?

Why would I need to use a primitive accessor methods in a core data project?
I'm reading about Core Data and note the below:
By default, Core Data dynamically
creates efficient public and primitive
get and set accessor methods for
modeled properties (attributes and
relationships) of managed object
classes...
For example, given an entity with an
attribute firstName, Core Data
automatically generates firstName,
setFirstName:, primitiveFirstName, and
setPrimitiveFirstName:.
I'm still not sure what the primitive accessor methods are? How do they work? When & why would I need to use them over the normal accessor methods?
thanks
In normal classes, you would not usually use primitive accessors, but Core Data uses them frequently. The most common scenario: You write a custom accessor (to perform maintenance, create a default object, handle transient wrapper of persistent property, etc.) but want to use Core Data's optimized storage. If the optimized accessors were normal accessors, your custom one would prevent it from being available, but instead you just have to use the primitive accessor.
Also, the default accessors you get from Xcode include methods to add or remove objects from to-many relationships. If these methods used normal accessors, the normal accessors would trigger change notifications for the entire set. Instead they use the primitive accessors and create their own change notifications for just the part they are changing.
The most important thing is that the primitive accessors are the only way to get to the optimized storage. Without them, you would have to use instance variables, which Apple advises against.
If you are writing your own methods in a subclass of NSManagedObject, the primitive accessors enable you to get directly at the data the object contains.
Effectively, you would use them the same way you would use an instance variable in a normal class.
The primary use of primitive accessors is to prevent key-value observing notifications from being sent when you change a value. Sometimes you do not want such notifications sent because they have quite a bit of overhead. E.g. when importing large sets of data or when you use a transitory value to alter a persisted value.
You use them almost always when writing customer accessor methods. If you look at the accessor methods generated by Xcode for managed object subclasses, you can see how they are used.