IOS4 note 7

 

An Instance Reference Is a Pointer

In Objective-C, if a variable is an  instance of  the class MyClass,  that variable  is of type MyClass* — a pointer  to a MyClass. In general, in Objective-C, a reference to an instance is a pointer and the name of the data type of what’s at the far end of that pointer is the name of the instance’s class.

 

 

Instance References, Initialization, and nil

 

Merely  declaring  an  instance  reference’s  type  doesn’t  bring  any  instance  into existence. For example:

NSString* s; // only a declaration; no instance is pointed to

After that declaration, s is typed as a pointer to an NSString, but it is not  in fact pointing to an NSString. You have created a pointer, but you haven’t supplied an NSString for it to point to.It is claiming to be a pointer to an NSString, and so your code might proceed to treat it as a pointer to an NSString.But  it  is pointing at garbage.

A pointer pointing at garbage is liable  to cause  serious  trouble  down  the  road when  you  accidentally  try  to  use  it  as  an  instance. Sending a message to a garbage pointer, or otherwise treating it as a meaningful instance, can crash your program.

For  this  reason,  if you aren’t going  to  initialize an  instance  reference pointer at  the moment you declare it by assigning it a real value, it’s a good idea to assign it nil:

NSString* s = nil; 

 

It’s simply a form of zero — the form of zero appropriate to an instance reference.The nil value simply means: “This instance reference isn’t pointing to any instance.”

 

 

 

No Overloading

 

It is illegal for two methods of the same type (class method or instance method) to exist in the same class with the same name but different signatures.

There are  languages that permit this  feature, called overloading, but Objective-C is not one of them.

 

 

 

The id Type

 

Objective-C  also provides  a  special  type designed  to  silence  the  compiler’s worries about object data types altogether. This is the id type. An id is a pointer, so you don’t say id*. It is defined to mean “an object pointer,” plain and simple, with no further specification.

Thus, every instance reference is also an id.Any object value can be assigned or typecast to an id, and vice versa.

nil is a form of zero, it's zero cast as an id.

 

Of course, it still makes a difference at runtime whether an id is nil or something else; sending a message to nil won’t crash the program, but sending an unknown message to an actual object will.

 

The compiler’s type checking is called static typing, as opposed to the dynamic behavior that takes place when the program actually runs. What I’m saying here, then, is that I prefer to take advantage of static typing as much as possible.

 

 

 

Messages as Data Type

 

@selector(myMethod:)

 

The term @selector() is a directive to the compiler, telling it that what’s in parentheses is a message name. Notice that what’s in parentheses is not an NSString; it’s the bare message name. And because it is the name, it must have no spaces and must include any colons that are part of the message name.So  the  rule  is  extremely  easy:  when  a  SEL  is  expected,  you’ll  usually  pass  a

@selector() expression.

 

 

C Functions and Struct Pointers

 

 

Moreover, many Objective-C objects and methods have  lower-level C counterparts.For  example,  besides  the  Objective-C  NSString,  there  is  also  something  called  a CFString; the “CF” stands for “Core Foundation,” which is a lower-level C-based API.A CFString is an opaque C struct (“opaque” means that the elements constituting this struct are kept secret, and  that you should operate on a CFString only by means of appropriate functions). As with an NSString or any other object, in your code you’ll typically refer to a CFString by way of a C pointer; the pointer to a CFString has a type name, CFStringRef (a “reference to a CFString,” evidently). You work with a CFString in pure C, by calling functions.

You might, on occasion, actually have to work with a Core Foundation type even when a

corresponding object type exists. For example, you might find that NSString, for all its power, fails to

implement a needed piece of functionality, which is in fact available for a CFString. Luckily, an NSString

(a value typed as NSString*) and a CFString (a value typed as CFStringRef) are interchangeable: you

can use one where the other is expected, though you will have to typecast in order to quiet the worries

of the compiler. The documentation describes this interchangeability by saying that NSString and CFString are

“toll-free bridged” to one another. To illustrate, I’ll use a CFString to convert an NSString representing an integer to that integer. (This

use of CFString is unnecessary, and is just by way of demonstrating the syntax; NSString has an

intValue method.)

NSString* answer = @"42"; int ans = CFStringGetIntValue((CFStringRef)answer); The typecast prevents the compiler from complaining, and works because NSString is toll-free

bridged to CFString — in effect, behind the scenes, an NSString is a CFString.

 

Cocoa defines a number of underlying pointer-to-struct C data types,whose name  typically ends  in “Ref”  (CGColorSpaceRef, CGPathRef,and so on).  It  is sometimes necessary  to assign one of  these  to an id variable or parameter. For example, a CALayer’s setContents: method expects an id parameter, but the actual value must be a CGImageRef. This is legal, because a pointer is just a pointer, but the compiler will complain unless you also typecast to an id or a pointer-to-void (void*).

 

You might even have reason to write your own C functions as part of a class, instead of writing a method. A C function has lower overhead than a full-fledged method; so even though it lacks the object-oriented abilities of a method, it is sometimes useful to write one, as when some utility calculation must be called rapidly and frequently. Also, once in a while you might encounter a Cocoa method or function that requires you to supply a C function as a “callback.”

An example is the NSArray method sortedArrayUsingFunction:context:. The first parameter is typed like this:

NSInteger (*)(id, id, void *)

That expression denotes, in the rather tricky C syntax used for these things, a pointer to a function that takes three parameters and returns an NSInteger. The three parameters of the function are an id, an id, and a pointer-to-void (which means any C pointer). The address operator (see Chapter 1) can be used to obtain a pointer to a C function. So to call sortedArrayUsingFunction:context: you’d need to write a C function that meets this description, and use its name, preceded by an ampersand, as the first argument.

 

To illustrate, I’ll write a “callback” function to sort an NSArray of NSStrings on the last character of each string. (This would be an odd thing to do, but it’s only an example!)

The NSInteger returned by the function has a special meaning: it indicates whether the

first parameter  is to be considered  less than, equal to, or  larger than the second. I’ll obtain it by calling the NSString compare: method, which returns an NSInteger with that same meaning. Here’s the function:

 

NSInteger sortByLastCharacter(id string1, id string2, void* context) {

    NSString* s1 = (NSString*) string1;

    NSString* s2 = (NSString*) string2;

    NSString* string1end = [s1 substringFromIndex:[s1 length] - 1];

    NSString* string2end = [s2 substringFromIndex:[s2 length] - 1];

    return [string1end compare:string2end];

}

And here’s how we’d call sortedArrayUsingFunction:context: with that function as our callback (assume that arr is an NSArray of strings):

NSArray* arr2 = [arr sortedArrayUsingFunction:&sortByLastCharacter context:NULL];

 

 

 

Blocks

 

 

A block is an extension to the C language, introduced in Mac OS X 10.6 and available if you’re compiling for iOS 4.0 or later. It’s a way of bundling up some code and handing off that entire bundle as an argument to a C function or Objective-C method. This is similar to what we did at the end of the preceding section, handing off a pointer to a function as an argument, but instead we’re handing off the code itself. The latter has some major advantages over the former, which I’ll discuss in a moment.

As an example, I’ll rewrite the preceding example to use a block instead of a function pointer.  Instead of calling sortedArrayUsingFunction:context:,  I’ll call sortedArrayUsingComparator:, which takes a block as its parameter. The block is typed like this:

NSComparisonResult (^)(id obj1, id obj2)

That’s similar to the syntax for specifying the type of a pointer to a function, but a caret character is used instead of an asterisk character. So this means a block that takes two id parameters and  returns an NSComparisonResult  (which  is merely an NSInteger, with just the same meaning as in the previous example). We can define the block and hand it off as the argument to sortedArrayUsingComparator: all in a single move, like this:

 

NSArray* arr2 = [arr sortedArrayUsingComparator: ^(id obj1, id obj2) {

    NSString* s1 = (NSString*) obj1;

    NSString* s2 = (NSString*) obj2;

    NSString* string1end = [s1 substringFromIndex:[s1 length] - 1];

    NSString* string2end = [s2 substringFromIndex:[s2 length] - 1];

    return [string1end compare:string2end];

}];

The syntax of the inline block definition is:

^ (id obj1, id obj2)  {

First, the caret character.

Then, parentheses containing the parameters.

Finally, curly braces containing the block’s content.

Thanks  to  the block, as you can see, we’ve combined  the definition of  the callback function with  its use. Of course, you might object that this means the callback  isn’t reusable; if we had two calls to sortedArrayUsingComparator: using the same callback, we’d have to write out the callback in full twice. To avoid such repetition, a block can be assigned to a variable:

 

NSComparisonResult (^sortByLastCharacter)(id, id) = ^(id obj1, id obj2) {

    NSString* s1 = (NSString*) obj1;

    NSString* s2 = (NSString*) obj2;

    NSString* string1end = [s1 substringFromIndex:[s1 length] - 1];

    NSString* string2end = [s2 substringFromIndex:[s2 length] - 1];

    return [string1end compare:string2end];

};

NSArray* arr2 = [arr sortedArrayUsingComparator: sortByLastCharacter];

NSArray* arr4 = [arr3 sortedArrayUsingComparator: sortByLastCharacter];

 

The return type  in an  inline block definition  is usually omitted. If  included, it follows the caret character, not in parentheses. If omitted, you may have to use typecasting in the return line to make the returned type match the expected type.

 

 

Variables in scope at the point where a block is defined keep their meaning within the block at that moment, even though the block may be executed at some later moment. (Technically, we say that a block is a closure.) It is this aspect of blocks that makes them useful for specifying functionality to be executed at some later time, or even in some other thread.

Variables in scope whose meaning is captured by the closure are protected from direct assignment  from within  the block, unless  you deliberately  turn off  this protection. Thus, if code inside a block tries to assign directly to a variable whose meaning comes from outside the block, the compiler will prevent it. To turn off this protection, declare the variable using  the __block qualifier. But of course  if such a variable  is an object reference, messages can be sent to it and the object may be mutated (because message sending is not assignment) even without the __block qualifier.

Examples in this book may or may not use blocks, depending on the system version for which the example is written. If I quote code from one of my apps that runs on a pre-4.0 version of  the  system,  that code can’t  involve blocks.  If  I write an example targeted purely at iOS 4.0 or later, I’ll feel free to use blocks.

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值