Functions and return in OOP - objective-c

I'm currently trying to learn Objective C and by this way, Oriented Object languages.
I'm declaring variables from a class I've written, but, my functions are way too long, and I'd like to cut that code off.
I do not know how the return works with classes and that's my problem.
Grapejuice *juice;
juice = [[Grapejuice alloc] init];
[juice setName:#"Grape juice"];
[juice setOrderNumber:1000];
[juice setPrice:1.79];
This, is part of a main in which I'm doing this to several objects, how can I do that in a separated function, and still got these informations out of this new function to be re-used later (to be printed for example) ?
Not sure if I'm clear but I've just started learning it yesterday, still hesitating on the basics.
Thanks homies.

If I understand you correctly, I believe what you want is a custom "init" method for your Grapejuice class.
In Grapejuice.h, add:
- (instancetype)initWithName:(NSString *)name orderNumber:(NSInteger)number price:(double)price;
In Grapejuice.m, add:
- (instancetype)initWithName:(NSString *)name orderNumber:(NSInteger)number price:(double)price {
self = [super init];
if (self) {
_name = name;
_orderNumber = number;
_price = price;
}
return self;
}
Then to use that code you do:
Grapejuice *juice = [[Grapejuice alloc] initWithName:#"Grape Juice" orderNumber:1000 price:1.79];
Please note that you may need to adjust the data types for the orderNumber and price parameters. I'm just guessing. Adjust them appropriately based on whatever type you specified for the corresponding properties you have on your Grapejuice class.

Related

Objective C - How to use inheritance to limit the types of classes entered into a method or array, and read those objects at a later time? [duplicate]

This question already has answers here:
Is there any way to enforce typing on NSArray, NSMutableArray, etc.?
(11 answers)
Closed 9 years ago.
How can I limit the type of objects put in an array if the limited objects are all inherited from a superclass?
So for instance, I have a parent class called
parentObj
I then have 3 child classes that have parameters that are added and not available to the superclass (parentObj)
childClass1
childClass2
childClass3
Then I have some other classes that are not related but I want to stay out of the array I'm trying to build up
otherClass1
otherClass2
I have this mutable array
NSMutableArray *arrayOfChildren;
that I want built up primarily of the three child classes of parentObj and not be able to contain the otherClasses
I don't want to build a different method to read and write the child classes to the array for each child class, because there could very well be more child classes that I build!
How can I have one method to add those classes to the array, and one to read them, including the child's added parameters?
The primary way I handle this problem was actually taught to me by a PHP book I was reading. Obviously PHP is not as strict as Objective C, so I had to do some changes.
I feel that this is a very useful skill to know how to do, especially for game programmers, where an array might need to carry hundreds of objects, all restricted to a certain type.
The nice thing about inheritance, is that the child classes also take on the "type" of their parent/ grandparent classes (and as far as you can go up if your tree of classes is long).
For example, if I had a method that had a parameter of type parentObj, you could put any of its children in that parameter slot and the code will run.
- (BOOL) addObjectToArray: (parentObj *) obj {
[array addObjectToArray:obj];
return true;
}
BOOL worked = [self addObjectToArray:childClass1];
[self addObjectToArray:childClass2];
[self addObjectToArray:childClass3];
[self addObjectToArray:otherClass1];
the code will run all the way up to the last line, in which it won't work properly. otherClass1 is not of type parentObj, so it won't work. This has successfully allowed us to limit the types of classes that the array can hold in one easy method!
Now reading the parameters from the objects is our next step to tackle. I'm sure there are other easier ways to do it, but this is how I do it.
I put a parameter in the super class (an integer) that will hold a so called ID for the child class.
parentObj.h:
//...
- (id) initWithProperties...:() :() :()... andID: (int)idType;
#property(nonatomic) int type;
//...
parentObj.m:
//...
- (id) initWithProperties...:() :() :()... andID: (int)idType {
//...
self.type = idType;
//...
}
//...
childClass1.h:
//...
#property(nonatomic) int someOtherPropertyOfChild1;
//...
childClass1.m:
//...
- (id) init {
self = [super initWithProperties... ...andID:1];
if (self) {
}
return self;
}
//...
childClass2.h:
//...
#property(nonatomic) int someOtherPropertyOfChild2;
//...
childClass2.m:
//...
- (id) init {
self = [super initWithProperties... ...andID:2];
if (self) {
}
return self;
}
//...
etc...
You need to remember which ID correlates to which child class, otherwise you are bound to get errors.
So now say you had a for loop that cycled through all the objects in the array full of classes. And say we needed to print out that extra parameter in each child class, how would we do that? I will show you how.
let's assume the variable being iterated in the for loop is x.
switch([array objectAtIndex:x].type) {
case 1:
//remember that childClass1 is id of one
childClass1 *CC1 = [array objectAtIndex:x];
NSLog(#"%d", CC1.someOtherPropertyOfChild1);
break;
//...
if the default case is called, that means that the object it is getting from the array is a parentObj object, or a child class that is not ID'd correctly.
I hope that this helps you in your troubles, and I hope it helps you understand why inheritance is important, and why you should use it!
Create a wrapper method that you use to add objects to the array:
- (void)addObject:(id)object
{
if ([object isKindOfClass:[parentObj class]])
{
[self.arrayOfChildren addObject:object];
}
}
You could also add an isMemberOfClass check if you wanted to also exclude instances of the parentObj class itself.

Singleton Design Implementation

As per my previous question, here, I've adapted my Data Controller class over to use a singleton design pattern so that I can use it only once across multiple views. However I do have a couple question I can't seem to find the solution too.
Firstly I'm not exactly sure how to call the class/object in the two views to make it work, and secondly I've made the initialisation method global with + but do I need to do this with each of the methods?
The initialisation of of the class that I want to be able to share across the views, in order to share the data, is
static SpeecherDataController *_instance = nil; // <-- important
+(SpeecherDataController *)instance
{
// skip everything
if(_instance) return _instance;
// Singleton
#synchronized([SpeecherDataController class])
{
if(!_instance)
{
_instance = [[self alloc] init];
// NSLog(#"Creating global instance!"); <-- You should see this once only in your program
}
return _instance;
}
return nil;
}
The class uses three Mutable Arrays as the main content which need to be both set and read in the two views.
If I understand your questions correctly, I think the answers are:
You can use something like:
SpeecherDataController * localReference = [SpeecherDataController instance];
and then later:
[localReference someMessage:param]; // or ...
localReference.property = whatever;
No, the methods on your SpeecherDataController class do not also need to be made class methods (i.e., they do not need to have the + prefix, they can use - if you want to access ivars within them).
Note: I think you want to replace [[self alloc] init]; with [[SpeecherDataController alloc] init]; in your implementation of instance.
(Also, note: I was unable to follow your link to "here" above to see your previous question. So my apologies if I misunderstood something.)

Does using parameters in methods change anything about the method's function?

I've tried searching google and this site regarding my question but found no answer.
I'm a beginner with Obj-C and would like this question answered.
What is the benefit of using parameters in my methods.
for example..
-(id)initWithName:(NSString *)newName atFrequency:(double)newFreq {
self = [super init];
if (self != nil) {
name = newName;
frequency = newFrequency;
}
return self;
}
versus
-(void)myMethod {
self = [super init];
if (self != nil) {
name = newName;
frequency = newFrequency;
}
return self;
}
I understand that the -(void) means the method has no return type, and the -(id) means that the first method has 'id' as a return type, and 'id' is generic....
can anyone help explain? I hope my question makes sense, thank you all for your help.
Parameters are inputs to a method, just like function/method parameters in any language. In your second example, on the line frequency = newFrequency;, where is newFrequency supposed to come from?
In other languages, where you might have something like
void initWithName(string newName, double newFreq);
In Obj-C the equivalent is
- (void)initWithName:(NSString *)newName atFrequency:(double)newFreq;
The difference is that in Obj-C, there is an extra piece of the method name for each parameter (like the atFrequency) — in this case, the method name is initWithName:atFrequency:, not just initWithName:.
(This is actually optional, you only have to have a : for each parameter. Technically initWithName:: is still a valid method name, but that's not considered good practice in Obj-C.)
See also:
How do I pass multiple parameters in Objective-C?
Is there a language out there in which parameters are placed inside method name?

Help with Wikibooks WikiDraw Obj-C application

I decided to start learning some Obj-C. And I thought that Wikibooks wikidraw application would be a good place to start (after some very basic "Hello World" programs). I've followed the chapters and now I'm at the end of "WikiDraws view class". So now I'm supposed to be able to compile and run. Of course it dosen't work. I got a lot of errors at first but i have fixed most of them, only 6 remaining. This is one of them:
- (void) mouseDragged:(NSPoint) pt
{
NSPoint np;
np.x = pt.x - _anchor.x;
np.y = pt.y - _anchor.y;
if ( _dragState == 0) {
// dragging of object
[self offsetLocationByX:np.x byY:np.y];
}
else if ( _dragState >= 1 && _dragState < 9 )
{
// dragging a handle
NSRect nb = [self newBoundsFromBounds:[self bounds] forHandle:_dragState withDelta:np];
[self setBounds:nb];
}
}
- (NSRect) newBoundsFromBounds:(NSRect) old forHandle:(int) whichOne withDelta:(NSPoint) p
{
// figure out the desired bounds from the old one, the handle being dragged and the new point.
NSRect nb = old;
switch( whichOne )
{ ..........
So at
NSRect nb = [self newBoundsFromBounds:...
I get an error message, "Invailid initializer" and "WKDShape may not respond to '-newBoundsFromBounds:forHandle:withDelta:"- . What should I do? I'm new to coding but eager to learn.
/Carl-Philip
Assuming you've pasted that code in the order written in your source code and newBoundsFromBounds:forHandle:withDelta: isn't declared (as distinct from being defined) at some earlier point, I think the problem is just that at nb = [self newBoundsFromBounds:... the compiler doesn't yet know what the return type will be. An NSRect is a C-style struct rather than an Objective-C class, so the compiler really does need to know.
As a solution, either put the definition of newBoundsFromBounds:... before mouseDragged:, add it to the #interface in your header file if you want it to be exposed to everyone or declare it internally to the implementation file as a category method. To do the final one, add the following to the top of your .m, assuming your class is called WikiDrawsView:
#interface WikiDrawsView (private)
- (NSRect)newBoundsFromBounds:(NSRect) old
forHandle:(int) whichOne
withDelta:(NSPoint) p;
#end
The 'private' is just a name you get to pick, it has no special meaning. Something like 'private' is often used to signify that you're using a category in a similar way that you might use private class member functions in C++ or a language like that.
The quick way to describe categories is that they patch additional methods onto existing classes at runtime, and they use the #interface [classname] ([category name]) syntax, with no member variable section. I'm sure your tutorial will get to them, Apple's documentation on them is here. This is a common use of categories but not the primary use.
To address the "WKDShape may not respond" warning, make sure you declare -newBoundsFromBounds:forHandle:withDelta: before -mouseDragged:. You can add it to the public interface in "WKDShape.h", or in an anonymous category in "WKDShape.m".

How to call a method in init method?

My program looks like this:
-(id)init
{
if ( (self = [super init]) )
{
//TargetWithActions *targetActions= [[TargetWithActions alloc] init];
[self countDownSpeed123];
}
return self;
}
-(void)countDownSpeed123
{
countDownSpeed = 5.0f;
}
#end
warning: 'TargetWithActions' may not respond to '-countDownSpeed123'
I am getting the warning in this way. Where I am wrong in my program. Please explain ?
Thank You.
If I need to use the countDownSpeed value in another class, how can I retain the value ? How can I use in the other class? I think retain works for pointer types.
EDIT:
Sorry for my bad coding and negligence. I have did mistakes in my program which are very blunt.
Thanks for answering.
First: I did not declare the
function (
-(void)countDownSpeed123; )in
interface.
Second: I did not include the
following in my class where I needed
the (countDownSpeed) value.
TargetWithActions *targetActions= [[TargetWithActions alloc] init];
[targetActions countDownSpeed123];
Now, I got what I need.
Thank You.
In the class where you trying to use
TargetWithActions, and in TargetWithActions.m make sure you
have #import
"TargetWithActions.h".
In TargetWithActions.h make sure
in your class declaration
you declared the method -(void)countDownSpeed123;
Sorry I don't understand what are you trying to do with countDownSpeed123, it does not return anything (void) so I'm not quite sure what you want to retain. If the method returns simple value like float or int you don't have to retain it, it is passed by value - it will be copied.
Sorry for my bad coding and negligence. I have did mistakes in my program which are very blunt. Thanks for answering.
First: I did not declare the function ( -(void)countDownSpeed123; )in interface.
Second: I did not include the following in my class where I needed the (countDownSpeed) value.
TargetWithActions *targetActions= [[TargetWithActions alloc] init];
[targetActions countDownSpeed123];
Now, I got what I need.
Thank You.