您的位置:首页 > 移动开发 > Objective-C

Ry’s Objective-C Tutorial---Methods

2015-11-22 00:01 519 查看




Tutorials 

Purchases 

About



You’re reading Ry’s Objective-C
Tutorial


Methods

Methods represent the actions that an object knows how to perform. They’re the logical counterpart to properties, which represent an object’s data. You can think of methods as functions that are attached to an object; however, they have a very different syntax.

In this module, we’ll explore Objective-C’s method naming conventions, which can be frustrating for experienced developers coming from C++, Java, Python, and similar languages. We’ll also briefly discuss Objective-C’s access
modifiers (or lack thereof), and we’ll learn how to refer to methods using selectors.


Naming Conventions

Objective-C methods are designed to remove all ambiguities from an API. As a result, method names are horribly verbose, but undeniably descriptive. Accomplishing this boils down to three simple rules for naming Objective-C methods:
Don’t abbreviate anything.
Explicitly state parameter names in the method itself.
Explicitly describe the return value of the method.

Keep these rules in mind as you read through the following exemplary interface for a 
Car
 class.
// Car.h

#import
<Foundation/Foundation.h>


@interface
Car
:
NSObject


// Accessors

-
(
BOOL
)
isRunning
;

-
(
void
)
setRunning:
(
BOOL
)
running
;

-
(
NSString
*
)
model
;

-
(
void
)
setModel:
(
NSString
*
)
model
;


// Calculated values

-
(
double
)
maximumSpeed
;

-
(
double
)
maximumSpeedUsingLocale:
(
NSLocale
*
)
locale
;


// Action methods

-
(
void
)
startEngine
;

-
(
void
)
driveForDistance:
(
double
)
theDistance
;

-
(
void
)
driveFromOrigin:
(
id
)
theOrigin
toDestination:
(
id
)
theDestination
;

-
(
void
)
turnByAngle:
(
double
)
theAngle
;

-
(
void
)
turnToAngle:
(
double
)
theAngle
;


// Error handling methods

-
(
BOOL
)
loadPassenger:
(
id
)
aPassenger
error:
(
NSError
**
)
error
;


// Constructor methods

-
(
id
)
initWithModel:
(
NSString
*
)
aModel
;

-
(
id
)
initWithModel:
(
NSString
*
)
aModel
mileage:
(
double
)
theMileage
;


// Comparison methods

-
(
BOOL
)
isEqualToCar:
(
Car
*
)
anotherCar
;

-
(
Car
*
)
fasterCar:
(
Car
*
)
anotherCar
;

-
(
Car
*
)
slowerCar:
(
Car
*
)
anotherCar
;


// Factory methods

+
(
Car
*
)
car
;

+
(
Car
*
)
carWithModel:
(
NSString
*
)
aModel
;

+
(
Car
*
)
carWithModel:
(
NSString
*
)
aModel
mileage:
(
double
)
theMileage
;


// Singleton methods

+
(
Car
*
)
sharedCar
;


@end

[/code]


Abbreviations

The easiest way to make methods understandable and predictable is to simply avoid abbreviations. Most Objective-C programmer expectmethods to be written out in full, as
this is the convention for all of the standard frameworks, from Foundation to UIKit.
This is why the above interface chose 
maximumSpeed
 over the more concise 
maxSpeed
.


Parameters

One of the clearest examples of Objective-C’s verbose design philosophy is in the naming conventions for method parameters. Whereas C++, Java, and other Simula-style languages treat a method as a separate entity from its parameters, an Objective-C method name
actually contains the names of all its parameters.

For example, to make a 
Car
 turn by 90 degrees in C++, you would call something like 
turn(90)
.
But, Objective-C finds this too ambiguous. It’s not clear what kind of argument 
turn()
 should take—it could be the new orientation, or it could be an angle by which to increment
your current orientation. Objective-C methods make this explicit by describing the argument with a preposition. The resulting API ensures the method will never be misinterpreted: it’s either 
turnByAngle:90
 or 
turnToAngle:90
.

When a method accepts more than one parameter, the name of each argument is also included in the method name. For instance, the above
initWithModel:mileage:
 method explicitly
labels both the 
Model
argument and the 
mileage
 argument. As we’ll see in a moment, this makes
for very informative method invocations.


Return Values

You’ll also notice that any methods returning a value explicitly state what that value is. Sometimes this is as simple as stating the class of the return type, but other times you’ll need to prefix it with a descriptive adjective.

For example, the factory methods start with 
car
, which clearly states that the method will return an instance of the 
Car
 class.
The comparison methods 
fasterCar:
 and 
slowerCar:
 return the faster/slower of the receiver
and the argument, and this is also clearly expressed in the API. It’s worth noting that singleton methods should also follow this pattern (e.g., 
sharedCar
), since the conventional 
instance
 method
name is ambiguous.

For more information about naming conventions, please visit the official Cocoa
Coding Guidlines.


Calling Methods

As discussed in the Instantiation and Usage section, you invoke a method by
placing the object and the desired method in square brackets, separated by a space. Arguments are separated from the method name using a colon:
[
porsche
initWithModel:
@"Porsche"
];

[/code]

When you have more than one parameter, it comes after the initial argument, following the same pattern. Each parameter is paired with a label, separated from other arguments by a space, and set off by a colon:
[
porsche
initWithModel:
@"Porsche"
mileage:
42000.0
];

[/code]

It’s a lot easier to see the purpose behind the above naming conventions when you approach it from an invocation perspective. They make method calls read more like a human language than a computer one. For example, compare the following method call from Simula-style
languages to Objective-C’s version:
// Python/Java/C++

porsche
.
drive
(
"Home"
,
"Airport"
);


// Objective-C

[
porsche
driveFromOrigin:
@"Home"
toDestination:
@"Airport"
];

[/code]

It might be more to type, but that’s why Xcode comes with such a nice auto-completion feature. You’ll appreciate the verbosity when you leave your code for a few months and come back to fix a bug. This clarity also makes it much easier to work with third-party
libraries and to maintain large code bases.


Nested Method Calls

Nesting method calls is a common pattern in Objective-C programs. It’s a natural way to pass the result of one call to another. Conceptually, it’s the exact same as chaining methods, but the square-bracket syntax makes them look a little bit different:
// JavaScript

Car
.
alloc
().
init
()


// Objective-C

[[
Car
alloc
]
init
];

[/code]

First, the 
[Car alloc]
 method is invoked, then the 
init
 method is called on its return value.


Protected and Private Methods

There are no protected or private access modifiers for Objective-C methods—they are all public. However, Objective-C does provide alternative organizational paradigms that let you emulate these
features.

“Private” methods can be created by defining them in a class’s implementation file while omitting them from its interface file. Since other objects (including subclasses) are never supposed to import the implementation, these methods are effectively hidden
from everything but the class itself.

In lieu of protected methods, Objective-C provides categories, which are a more general solution
for isolating portions of an API. A full example can be found in “Protected” Methods.


Selectors

Selectors are Objective-C’s internal representation of a method name. They let you treat a method as an independent entity, enabling you to separate an action from the object that needs to perform it. This is the basis of the target-action design pattern, which
is introduced in the Interface Builder chapter of Ry’s
Cocoa Tutorial. It’s also an integral part of Objective-C’s dynamic typing system.

There are two ways to get the selector for a method name. The
@selector()
 directive lets you convert a source-code method name to a selector, and the 
NSSelectorFromString()
 function
lets you convert a string to a selector (the latter is not as efficient). Both of these return a special data type for selectors called 
SEL
. You can use 
SEL
 the
exact same way as 
BOOL
int
, or any other data type.
// main.m

#import
<Foundation/Foundation.h>

#import
"Car.h"


int
main
(
int
argc
,
const
char
*
argv
[])
{

@autoreleasepool
{

Car
*
porsche
=
[[
Car
alloc
]
init
];

porsche
.
model
=
@"Porsche 911 Carrera"
;


SEL
stepOne
=
NSSelectorFromString
(
@"startEngine"
);

SEL
stepTwo
=
@selector
(
driveForDistance:
);

SEL
stepThree
=
@selector
(
turnByAngle:quickly:
);


// This is the same as:

// [porsche startEngine];

[
porsche
performSelector:
stepOne
];


// This is the same as:

// [porsche driveForDistance:[NSNumber numberWithDouble:5.7]];

[
porsche
performSelector:
stepTwo

withObject:
[
NSNumber
numberWithDouble:
5.7
]];


if
([
porsche
respondsToSelector:
stepThree
])
{

// This is the same as:

// [porsche turnByAngle:[NSNumber numberWithDouble:90.0]

//              quickly:[NSNumber numberWithBool:YES]];

[
porsche
performSelector:
stepThree

withObject:
[
NSNumber
numberWithDouble:
90.0
]

withObject:
[
NSNumber
numberWithBool:
YES
]];

}

NSLog
(
@"Step one: %@"
,
NSStringFromSelector
(
stepOne
))
;

}

return
0
;

}

[/code]

Selectors can be executed on an arbitrary object via 
performSelector:
and related methods. The 
withObject:
 versions
let you pass an argument (or two) to the method, but require those arguments to be objects. If this is too limiting for your needs, please see 
NSInvocation
for
advanced usage. When you’re not sure if the target object defines the method, you should use the 
respondsToSelector:
 check before trying to perform the selector.

The technical name for a method is the primary method name concatenated with all of its parameter labels, separated by colons. This makes colons an integral aspect of method names, which can be confusing to Objective-C beginners. Their usage can be summed up
as follows: parameterless methods never contain a colon, while methods that take a parameter always end in a colon.

A sample interface and implementation for the above 
Car
 class is included below. Notice how we have to use 
NSNumber
 instead
of 
double
for the parameter types, since the 
performSelector:withObject:
method doesn’t let
you pass primitive C data types.
// Car.h

#import
<Foundation/Foundation.h>


@interface
Car
:
NSObject


@property
(
copy
)
NSString
*
model
;


-
(
void
)
startEngine
;

-
(
void
)
driveForDistance:
(
NSNumber
*
)
theDistance
;

-
(
void
)
turnByAngle:
(
NSNumber
*
)
theAngle

quickly:
(
NSNumber
*
)
useParkingBrake
;


@end

[/code]
// Car.m

#import
"Car.h"


@implementation
Car


@synthesize
model
=
_model
;


-
(
void
)
startEngine
{

NSLog
(
@"Starting the %@'s engine"
,
_model
);

}


-
(
void
)
driveForDistance:
(
NSNumber
*
)
theDistance
{

NSLog
(
@"The %@ just drove %0.1f miles"
,

_model
,
[
theDistance
doubleValue
]);

}


-
(
void
)
turnByAngle:
(
NSNumber
*
)
theAngle

quickly:
(
NSNumber
*
)
useParkingBrake
{

if
([
useParkingBrake
boolValue
])
{

NSLog
(
@"The %@ is drifting around the corner!"
,
_model
);

}
else
{

NSLog
(
@"The %@ is making a gentle %0.1f degree turn"
,

_model
,
[
theAngle
doubleValue
]);

}

}


@end

[/code]


Summary

This module explained the reasoning behind Objective-C’s method naming conventions. We also learned that there are no access modifiers for Objective-C methods, and how to use 
@selector
 to
dynamically invoke methods.

Adapting to new conventions can be a frustrating process, and the dramatic syntactic differences between Objective-C and other OOP languages won’t make your life any easier. Instead of forcing Objective-C into your existing mental model of the programming universe,
it helps to approach it in its own right. Try designing a few simple programs before passing judgement on Objective-C’s verbose philosophy.

That covers the basics of object-oriented programming in Objective-C. The rest of this tutorial explores more advanced ways to organize your code. First on the list are protocols, which let you share an API between several classes.

 


Mailing List

Sign up for my low-volume mailing list to find out when new content is released. Next up is a comprehensive Swift tutorial
planned for late January.

Email Address:

You’ll only receive emails when new tutorials are released, and your contact information will never be shared with third parties. Click
here to unsubscribe.

© 2012-2014 

RyPress.com 

All Rights Reserved 

Terms of Service 

Privacy Policy
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: