Objective C Helper Methods - objective-c

Novice here attempting to understand inheritance. If I initialize a new object with several properties and I want other classes to help assign values to those properties, do I need to create instances of those other classes? Visualized:
-(ObjA *)init{
self = [super init];
self.property1 = [method from Class A];
self.property2 = [method from Class B];
self.property3 = [method from Class C]; etc...
return self;
}
In other words, assuming Class A, B, and C need to know what Object A is, would I need to make those class methods instance methods and initialize each object? Is there another way to go about this? Thank you in advance for your help.

In other words, assuming Class A, B, and C need to know what Object A
is
NO.
You can simply call a method from ClassA/B/C etc. But the return type must match with respective property.
Let, the property1 is for kind NSString then your ClassA method must be
-(NSString *)methodClassA{
...
return someStringValue;
}
Then you need to use:
ClassA *objClassA=[ClassA new];
self.property1=[objClassA methodClassA];
Or you can go with class method by this:
+(NSString *)methodClassA{
...
return someStringValue;
}
And using it as:
self.property1=[ClassA methodClassA];

assuming Class A, B, and C need to know what Object A is
The initialization code of an object should be self contained, unless it is using functionality owned by a different object, in which case the object acts as a client of that functionality. That is, objectA acts as client of A,B,C (as seen in your code).
But this doesn't imply that A,B,C need to know (have a dependency on) objectA. By doing that, you are saying that they don't have a reason to exist on their own.
In general,
Every class or method should have one encapsulated purpose. This makes it easy to understand, change, and test in isolation. It's a common pattern to create classes whose sole purpose is to encapsulate information to create a different class, but to split that in three different classes is beyond weird (as in, I can't imagine an example of that).
An object shouldn't be allowed to exist in an unusable state, nor should it require non essential information when it is created. Does objectA require those properties to function? if it does, your code is right, if it doesn't, the initializer is providing too much information and making it less reusable.
Try to rethink your doubt with a real (instead abstract) example. You may end up making sense of it yourself.

Related

Passing class objects as parameters in Objective C

Hey so I am new to Xcode and I have a few questions.
I want to make a Grade-book Application, that implements quite a few classes. For example, I created a class called "AssignmentList" which basically stores a list of assignment grades in the form of a double.
Another class, called "Course" has a NSMutableArray of AssignmentList objects.
If I wanted to retrieve an AssignmentList parameter for a course, my Java instinct would tell me to make a getter method like this:
-(AssignmentList)getAssignmentList(Course);
However, I can't seem to do that in Objective C, and only works when I do this:
-(id)getAssignmentList(Course);
How do I go about this? I wanted to create a UITableView listing all the AssignmentList objects of a Course, but I can't even set a UITableViewCell with the name of the AssignmentList because it won't let me use the getName method I made, because getName only works for an AssignmentList object, but the getAssignmentList method returns an (id).
Assuming an AssignmentList is a class with instances and not some kind of collection (e.g. an NSArray of Assignments), then your declaration needs to be something like:
-(AssignmentList *) getAssignmentList:(Course *) course;
The * is important: in Objective-C you don't really pass around objects, you pass around pointers to objects. (Well, that's true in Java, too, but you don't have to be explicit about it.)
When you declare something id that means pointer to something of unknown type so you don't need the *.

Class design plus object literals in Cocoa Obj-C

Let us say that application has a concept of cars in it. A car is an instance of Car. There are a small number of possible cars and most, but not all of the data about a car is known at design time. Each kind of car is a singleton; there is at most one of each kind of Car per app.*
Since they are singletons, and since they are named, that suggests some sugar. The most important piece of sugar is this: when I import "Car.h", into a file, I want the symbols "MAFerrari", "MAMercedes", and "MAMclauren" to start showing up in my autocomplete where ever code completion thinks I am trying to provide an instance of a Car*.
My next greedy desire is that I want to be able to send instance methods to my MAFerrari literal, e.g. [MAFerrari topSpeed] means "get the singleton instance of Car that corresponds to the Ferrari and send topSpeed to it", but I acknowledge the utter triviality of this. Even pragmatists should know what their Utopia looks like.
Finally, if possible, I want clean way to declare the constant properties of the three cars as literal data at the top of my Car.m file.
Now, again, I don't actually expect all of that to be possible in Objective C. I just want to know how close we can get to that all that.
The closest idea I've had is to subclass Car for each type of car and provide a +sharedInstance method for each one. sharedInstance can implement the singleton pattern: if it's initialized, return it, otherwise initialize it, store it (where? it should be private to the Car class hierarchy), then return it. Each subclass can implement its own initializer which contains the defaults for that subclass.
Here's what I don't like about this:
I think I have to import all the header files whenever I work with these subclasses. This absolutely sucks. Is there another way?
I have to create .m/.h file pair for every one of these subclasses. That seems like a lot of boilerplate, since they have no unique behavior.
[[MAFerrari sharedInstance] topSpeed] isn't quite as good as [MAFerrari topSpeed], but I acknowledge that this is trivial.
Anyway, how would you do it?
*In reality, it's not cars, but in-app purchase assets, for the curious.
It sounds like what you want is just a global variable. You can create a global variable named whatever you want (say, MAFerrari) and stick whatever you want in it — whether the contents of the variables are instances of multiple singleton classes or multiple instances of the same class doesn't really matter from the point of view of having global names to refer to the objects.
Easy-peasy.
Note that these aren't singletons; they're just long-lived instances of a class stored in global variables.
// Bolt.h
#import <Foundation/Foundation.h>
#interface Bolt : NSObject
// Properties
- (instancetype)initWithLength:(NSUInteger)length
diameter:(NSUInteger)diam
thread:(NSUInteger)thread
grade:(NSUInteger)grade;
// etc.
#end
extern Bolt * twentyFiveByTwelveCoarseThreadGradeEightBolt;
extern Bolt * fiftyByTenFineThreadGradeFiveBolt;
//
// Bolt.m
#import "Bolt.h"
Bolt * twentyFiveByTwelveCoarseThreadClassEightBolt;
Bolt * fiftyByTenFineThreadGradeFiveBolt;
// This will be run before main() but after classes are loaded
__attribute__((constructor))
static void initialize_global_Bolts(void)
{
twentyFiveByTwelveCoarseThreadClassEightBolt = [[Bolt alloc] initWithLength:25
diameter:12
thread:175
grade:8];
fiftyByTenFineThreadGradeFiveBolt = [[Bolt alloc] initWithLength:50
diameter:10
thread:1
grade:5];
}
#implementation Bolt
- (instancetype)initWithLength:(NSUInteger)length
diameter:(NSUInteger)diam
thread:(NSUInteger)thread
grade:(NSUInteger)grade
{
// Do initialization
}
#end
Now you can do things like [fiftyByTenFineThreadGradeFiveBolt maximumTorque]; wherever Bolt.h is imported.
You can't put dictionary or other literals at top level, because they resolve into method calls, which can't be used outside of other methods.

"Decorate" several classes with a specific method in Obj-C

I'm not yet that into design patterns so "Sorry!" to bother you with such a question, that might be obvious.
The thing is, I have several classes: Show, Segment, Command. These three classes are totally different, except the one thing: They all have an NSArray called schedules, which contains ScheduleItem classes.
In my workflow I need to check, if the current time matches a scheduleItem to set the Show,Segment or Command active. So, I'd like to have a method on all these three classes called isActive(). Since this method does the same for all current and future classes, I'm looking for a way to implement the isActive method just once, and reuse it in those classes.
Is there a nice way doing this?
To remember, those classes have absolutely nothing in common, except the schedules array. So, I'd like to avoid subclassing. But you can convince me otherwise.
You can create smth like this
#interface ScheduleCollection : NSObject {
NSArray* schedules;
}
#property NSArray* schedules;
/**
Return true if matches.
*/
-(BOOL) match:(ScheduleSclass); //or call it isActive or whatever you like
#end
Then replace schedules array in Show, Segment, Command with ivar of this class. If you need to compare time just get the property and call match:
Show* show = ...;
BOOL m = [show.schedules match: my_time];
There's really no design pattern for this except generic inheritance (shared base class with the method). You can't add it as a category for all three, as they don't share a base class.
If you want to avoid introducing a base class, you can use the fact that type id is a typeless object, and you can invoke any method on it at runtime. Only it will fail if the actual objec doesn't have the method...
On each of the objects, create a method called getSchedule like this:
- (NSArray*) getSchedule {
return schedule;
}
Then just create this method somewhere else
-(BOOL) isActive:(id)anyObjectWithGetScheduleAnyOtherWillFailWithSelectorNotImplemented
{
// You could do an explicit check to determine if the object passed in implements
// getSchedule, but I skipped it here.
NSArray* schedule = [anyObjectWithGetScheduleAnyOtherWillFailWithSelectorNotImplemented getSchedule];
<your implementation here>
}
In my opinion, you would be better off just introducing a shared base class, as it's a lot clearer and won't really take that much more work. But if you have good reasons not to, this will also do the job.

Why create custom init when ivars/properties can be set from outside the instance?

I'm reading an Objective-C book and I have a question that the book doesn't seem to really answer.
Let's say I have two custom-made classes.
The first class is called ClassA. It has both the .h and .m files of course. The second class is called ClassB. It also has both .h and .m files.
Somewhere in the code, 'ClassA' has this method:
-(IBAction)displaySomeText:(id)sender {
ClassB *myNumber = [[ClassB alloc]init];
NSString *numberString = [myNumber storedNumberAsString];
// storedNumberAsString is just a method that returns a string object that holds
// myVariable.
[textView insertText:numberString];
//textView is a object I created that just displays some text on screen.
[myNumber release];
}
The book tells me that ClassB should have a method:
-(id)init {
[super init]; //I know why this is done, the book explains it well.
myVariable = 42; // I created this variable already in the ClassB .h file
return self;
}
Now, when in the Interface Builder I click the buttons I connected, etc. It works, the number displayed is 42.
My question is, why do I have to create an -(id)init method for ClassB, if I can do the following in ClassA's method:
-(IBAction)displaySomeText:(id)sender {
ClassB *myNumber = [[ClassB alloc]init];
myNumber.myVariable = 42; //I just do this to skip the -(id)init method.
NSString *numberString = [myNumber storedNumberAsString];
[textView insertText:numberString];
[myNumber release];
}
Doing this, it still displays the same value: 42. I can change it to whatever I like. So why not just use the init inherited from NSObject and just do the simple way myNumber.myVariable = 42?
Suppose that the value of the instance variable were something more complicated than an integer. Suppose it involved reading a string from a file, or getting some information over the network, or just doing some arithmetic. In that case, it wouldn't make sense to have ClassA be responsible for setting that value correctly. That would break the encapsulation that makes it useful to have separate classes in the first place.
In this extremely simple case, you're quite right, there may be no reason to have a custom initializer for ClassB, but in general, a class should itself be responsible for its state being set up correctly. Foisting that responsibility off on other classes means that those others need to know about the internals of the first, meaning the two may be too tightly coupled.
In some cases, the value of the ivar might be a piece of information that is known only to ClassA, or needs to be calculated based on such a piece of information. Then you should create a custom initializer for ClassB which receives that value, e.g., - (id) initWithInteger: This would become the "designated initializer", and you would then override -[ClassB init] to call it with some reasonable default value.
If instances of ClassB do not have to have anything initialized (other than to nil/zero), you do not need to create an explicit init method for ClassB. In this case the question is whether setting myVariable to 42 is ClassB's answer to life, the universe, and everything, or whether myVariable is just a field in ClassB that could be set to any value.
That is, the issue is conceptual, not of physical significance. If conceptually the value 42 "belongs" to ClassB, then there should be an init method for ClassB that sets it. If that specific value has more meaning to ClassA than to ClassB then some method of ClassA should set it. If you do it "wrong" the code still works fine, but your design is slightly less elegant, slightly less extendable, slightly less robust.
This is kind of a tricky issue. I was "brought up" to think that after a constructor (initializer) runs, the object should be ready to go. You should be able to safely call any method on it. Therefore, you need to set up any instance variables in the constructor for which 0 is not a valid value. I like to set them up if they have 0 values anyway, just for sanity, because I never want to bother to know the minute details of every language I work with, like whether they initialize instance variables to 0 automatically.
However, there are some arguments for not initializing some variables.
The initialization is complex, like loading a file or getting data from the network. You want to keep open the possibility of creating an instance and waiting until you're ready to do heavy weight operations.
There are quite a lot of instance variables that are configurable. Your options are to make a constructor with umpteen arguments, or make a constructor with no or a few arguments, and let the caller decide which values should be set to non-default values by property setters.
You need to set up a whole object graph before you can meaningfully initialize a value. That is, initializing the value might have side effects that depend on other related objects. The best solution is to construct each object, then use property setters to set the relationships between objects, then use property setters to initialize attribute values.

Implementing a category within the implementation of another interface in Obj-C

I have a custom class in Obj-C called RouteManager which contains an array of NSStrings. Each string is a bus stop name which is used as a key for a dictionary to get the rest of the information for the bus stop (basically, just [busStopDictionary allkeys]). In one of the situations where my app uses this array, I want to return the array sorted by the distance from the user. I've started setting up the code to be able to call sortedArrayUsingSelector on my array with the following method:
- (NSComparisonResult)compareByDistance:(NSString*) otherStop
{
// Return appropriate NSOrdered enum here based on comparison of
// self and otherStop
}
My problem is that in the case where compareByDistance is a method of RouteManager, self refers to the instance of RouteManager. However, I need self to refer to the NSString that the compare is being called on. So, I assumed I needed to setup a category, as such:
#interface NSString (Support)
-(NSComparisonResult) compareByDistance:(NSString*)otherStop;
#end
This got my self reference correct, however this comparison uses values from the RouteManager class. When implemented as seen above, the NSString (Support) implementation obviously complains that those values are undeclared.
That should provide enough background info for my question. How do I go about doing this? I would like my category of NSString, which consists solely of the method compareByDistance, to be able to use values from the current instance of my class, RouteManager, which inherits from NSObject. Ideally, I feel as though the category should somehow be within RouteManager. I feel there has to be some way to accomplish this that is cleaner than passing the necessary values into compareByDistance. Thanks in advance for any and all help.
Your best bet would be to define a custom class for a bus stop, instead of storing them as strings and dictionaries.
Make the BusStop class have properties for Name, Location and whatever else. Implement the compareByDistance: method on the BusStop class.
You can still use a dictionary if you need to look them up by name. Just store them with the name as the dictionary's key, and the BusStop object as the dictionary's value.