1.In Objective-C, a class is itself an object with an opaque type called Class.
Classes can’t have properties defined using the declaration syntax shown earlier for instances, but they can receive messages.
2 Literals Offer a Concise Object-Creation Syntax
some classes allow you to use a more concise, literal syntax to create instances.
You can create an NSString instance, for example, using a special literal notation, like this:
NSString *someString = @"Hello, World!"; |
This is effectively the same as allocating and initializing an NSString or using one of its class factory methods:
NSString *someString = [NSString stringWithCString:"Hello, World!" |
encoding:NSUTF8StringEncoding]; |
The NSNumber class also allows a variety of literals:
NSNumber *myBOOL = @YES; |
NSNumber *myFloat = @3.14f; |
NSNumber *myInt = @42; |
NSNumber *myLong = @42L; |
NSArray and NSDictionary objects; NSArray *someArray = @[firstObject, secondObject, thirdObject];
NSDictionary *dictionary = @{
|
@"anObject" : someObject, |
@"helloString" : @"Hello, World!", |
@"magicNumber" : @42, |
@"aValue" : someValue |
}; |
It’s always a good idea to initialize scalar variables at the time you declare them, otherwise their initial values will contain garbage from the previous stack contents:
BOOL success = NO; |
int magicNumber = 42; |
This isn’t necessary for object pointers, because the compiler will automatically set the variable to nil if you don’t specify any other initial
value:
XYZPerson *somePerson; |
// somePerson is automatically set to nil |
If you want to use a different name for an accessor method, it’s possible to specify a custom name by adding attributes to the property. In the case of Boolean properties (properties that have a YES or NO value),
it’s customary for the getter method to start with the word “is.” The getter method for a property called finished, for example, should be called isFinished.
Again, it’s possible to add an attribute on the property:
@property (getter=isFinished) BOOL finished; |
5,Most Properties Are Backed by Instance Variables
firstName,
for example, the synthesized instance variable will be called_firstName.
@synthesize firstName = ivar_firstName; |
In this case, the property will still be called firstName, and be accessible through firstName and setFirstName:accessor
methods or dot syntax, but it will be backed by an instance variable called ivar_firstName.
You Can Define Instance Variables without Properties
use strong references for their synthesized instance variables. To declare a weak reference, add an attribute to the property, like this:
@property (weak) id delegate; |
If you don’t want a variable to maintain a strong reference, you can declare it as __weak, like this:
NSObject * __weak weakVariable; |
This means that if you use a weak variable in the previous date example:
NSDate * __weak originalDate = self.lastModificationDate; |
self.lastModificationDate = [NSDate date]; |
__weak is __strong.
Again, you don’t need to specify __strong explicitly,
because it is the default.copy property
must support NSCopying, which
means that it should conform to the NSCopying protocol.Categories Add Methods to Existing Classes
Any methods that you declare in a category will be available to all instances of the original class, as well as any subclasses of the original class. At runtime, there’s no difference between a method added by a category and one that is implemented by the original class.Class Extensions Extend the Internal Implementation
A class extension bears some similarity to a category, but it can only be added to a class for which you have the source code at compile time (the class is compiled at the same time as the class extension). The methods declared by a class extension are implemented in the@implementation block
for the original class so you can’t,for example, declare a class extension on a framework class, such as a Cocoa or Cocoa Touch class like NSString.Unlike regular categories, a class extension can add its own properties and instance variables to a class. If you declare a property in a class extension, like this:
@interface XYZPerson () |
@property NSObject *extraProperty; |
@end |
the compiler will automatically synthesize the relevant accessor methods, as well as an instance variable, inside the primary class implementation.
If you add any methods in a class extension, these must be implemented in the primary implementation for the class.
It’s also possible to use a class extension to add custom instance variables. These are declared inside braces in the class extension interface:
@interface XYZPerson () {
|
id _someCustomInstanceVariable; |
} |
... |
@end |
Use Class Extensions to Hide Private Information
@interface XYZPerson : NSObject |
... |
@property (readonly) NSString *uniqueIdentifier; |
- (void)assignUniqueIdentifier; |
@end |
@interface XYZPerson () |
@property (readwrite) NSString *uniqueIdentifier; |
@end |
|
|
@implementation XYZPerson |
... |
@end |
This means that the compiler will now also synthesize a setter method, so any method inside the XYZPersonimplementation will be able to set the
property directly using either the setter or dot syntax.
By declaring the class extension inside the source code file for the XYZPerson implementation, the information stays private to the XYZPerson class.
If another type of object tries to set the property, the compiler will generate an error.
Protocols Define Messaging Contracts
A class interface declares the methods and properties associated with that class. A protocol, by contrast, is used to declare methods and properties that are independent of any specific class.
The basic syntax to define a protocol looks like this:
@protocol ProtocolName |
// list of methods and properties |
@end |
Protocols Inherit from Other Protocols
@protocol MyProtocol <NSObject> |
... |
@end |
Protocols Are Used for Anonymity
NSInteger sectionNumber = ... |
id <NSFetchedResultsSectionInfo> sectionInfo = |
[self.fetchedResultsController.sections objectAtIndex:sectionNumber]; |
NSInteger numberOfRowsInSection = [sectionInfo numberOfObjects]; |
Even though you don’t know the class of the sectionInfo object, the NSFetchedResultsSectionInfo protocol
dictates that it can respond to the numberOfObjects message.
In order for this anonymousUtility object to be useful, the developer of the framework can publish a protocol that reveals some of its methods.
Even though the original class interface isn’t provided, which means the class stays anonymous, the object can still be used in a limited way:
id <XYZFrameworkUtility> utility = [frameworkObject anonymousUtility]; |
Represent Other Values Using Instances of the NSValue Class
The NSNumber class is itself a subclass of the basic NSValue class,
which provides an object wrapper around a single value or data item. In addition to the basic C scalar types, NSValue can also be used
to represent pointers and structures.
The NSValue class offers various factory methods to create a value with a given standard structure, which makes it easy to create an instance
to represent, for example, an NSRange, like the example from earlier in the chapter:
NSString *mainString = @"This is a long string"; |
NSRange substringRange = [mainString rangeOfString:@"long"]; |
NSValue *rangeValue = [NSValue valueWithRange:substringRange]; |
It’s also possible to create NSValue objects to represent custom structures. If you have a particular need to use a C structure (rather than
an Objective-C object) to store information, like this:
typedef struct {
|
int i; |
float f; |
} MyIntegerFloatStruct; |
you can create an NSValue instance by providing a pointer to the structure as well as an encoded Objective-C type. The @encode() compiler
directive is used to create the correct Objective-C type, like this:
struct MyIntegerFloatStruct aStruct; |
aStruct.i = 42; |
aStruct.f = 3.14; |
|
|
NSValue *structValue = [NSValue value:&aStruct |
withObjCType:@encode(MyIntegerFloatStruct)]; |
The standard C reference operator (&) is used to provide the address of aStruct for
the value parameter.
NSDictionary
NSNumber *storedNumber = [dictionary objectForKey:@"magicNumber"];
There’s also an alternative syntax to using objectForKey:, which looks like this:
NSNumber *storedNumber = dictionary[@"magicNumber"]; |
If you use fast enumeration with a dictionary, you iterate over the dictionary keys, like this:
for (NSString *eachKey in dictionary) {
|
id object = dictionary[eachKey]; |
NSLog(@"Object: %@ for key: %@", object, eachKey); |
} |
If you need to keep track of the current index, simply count the iterations as they occur:
int index = 0; |
for (id eachObject in array) {
|
NSLog(@"Object at index %i is: %@", index, eachObject); |
index++; |
} |
Represent nil with NSNull
It’s not possible to add nil to the collection classes described in this section because nil in
Objective-C means “no object.” If you need to represent “no object” in a collection, you can use the NSNull class:
NSArray *array = @[ @"string", @42, [NSNull null] ]; |
NSNull is a singleton class, which means that the null method
will always return the same instance. This means that you can check whether an object in an array is equal to the shared NSNull instance:
for (id object in array) {
|
if (object == [NSNull null]) {
|
NSLog(@"Found a null object"); |
} |
} |
Most Collections Also Support Enumerator Objects
It’s also possible to enumerate many Cocoa and Cocoa Touch collections by using an NSEnumerator object.
You can ask an NSArray, for example, for an objectEnumerator or
a reverseObjectEnumerator. It’s possible to use these objects with fast enumeration, like this:
for (id eachObject in [array reverseObjectEnumerator]) {
|
... |
} |
In this example, the loop will iterate over the collected objects in reverse order, so the last object will be first, and so on.
It’s also possible to iterate through the contents by calling the enumerator’s nextObject method repeatedly, like this:
id eachObject; |
while ( (eachObject = [enumator nextObject]) ) {
|
NSLog(@"Current object is: %@", eachObject); |
} |
本文详细介绍了Objective-C的基本概念、类与实例、属性、消息传递、nil处理、literals语法、类别与扩展、协议定义及使用、NSValue类应用、字典操作等核心编程技巧,覆盖了从入门到进阶的学习路径。

被折叠的 条评论
为什么被折叠?



