!!!Obj-C 2.0 -- Chapter 2 Defining a Class

本文详细介绍了Objective-C中类的定义方式,包括类接口和实现的分离、实例变量的作用域及访问控制、消息发送机制等内容。

In Objective-C, classes are defined in two parts:

  • An interface that declares the methods and instance variables of the class and names its superclass.
  • An implementation that actually defines the class.

These two parts usually split between two files, but we can also use category to use several files to define a class.

2.1 Source Files

The interface and implementation are usually separated into two different files. The interface file must be made available to anyone who uses the class.

It's customary to have a separate interface file for each class.

2.2 Class Interface

The declaration of a class interface begins with the compiler directive @interface and ends with the directive @end

@interface ClassName : ItsSuperclass
{
    instance variable declarations
}
method declarations
@end
Methods are declared after the braces enclosing instance variables and before the end of the class declaration.

The names of methods that can be used by class objects, class methods, are preceded by a plus sign:

+ alloc;
The methods that instances of a class can use, instance methods, are marked with a minus sign:

- (void) display;
Different between class/instance method: http://stackoverflow.com/questions/1053592/what-is-the-difference-between-class-and-instance-methods
Class method and instance method can have the same name. A method can have the same name as an instance variable.

Method return types and argument types are declared using the standard C syntax:

- (void)setRadius:(float)aRadius;
If a return or argument type isn't explicitly declared, it's assumed to be the default type for methods and messages --- an id.

When there's more than one argument, the arguments are declared within the method name after the colons:

- (void)setWidth:(float)width height:(float)height;

2.2.1 Importing the interface

The interface file must be included in any source module that depends on the class interface. The interface is usually included with the #import directive

#import "Rectangle.h"
#import is similar to #include, except that it makes sure the same file is never included more than once.

An interface file begins by importing the interface for its superclass:

#import "ItsSuperclass.h"
@interface ClassName : ItsSuperclass
{
    ......
}
......
@end

2.2.2 Referring to Other Classes

If the interface file mentions a class that is not in the hierarchy, it must:

1. import them explicitly

2. declare them with the @class directive

// inform compiler that Rectangle/Circle are class names
@class Rectangle, Circle;
An interface file mentions class names when it statically types instance variables, return values, and arguments:

//mentions NSColor class
- (void)setPrimaryColor:(NSColor *)aColor;
In the above case, we only need to know that NSColor is a class name, so @class directive gives the compiler sufficient forwarning of what to expect.

2.3 Class Implementation

The definition of a class begins with the @implementation directive and ends with the @end directive.

Every implementation file must import its own interface:

#import "ClassName.h"

@implementation ClassName
method definition
@end
Methods for a class are defined within a pair of braces:

+ (void)setFilled: (BOOL)flag
{
    ....
}

2.3.1 Referring to Instance Variables

By default, the definition of an instance method has all the instance variables of the object within its scope. It can refer to them simply by name:

- (void)setFilled: (BOOL) flag
{
    filled = flag;
    ...
}
When the instance variable belongs to an object that's not the receiver, the object's type must be made explicit to the compiler through static typing. In referring to the instance variable of a statically typed object, the structure pointer operator(->) is used.

2.3.2 The Scope of Instance Variables

An object's interface lies in its methods, not in its internal data structures.

To enforce the ability of an object to hide its data, the compiler limits the scope of instance variables.

DirectiveMenaing
@privateThe instance variable is accessible only within the class that declares it
@protectedThe instance variable is accessible within the class that declares it and within classes that inherit it.
@public The instance variable is accessible everywhere
@packageOn 64-bit, an @package instance variable acts like @public inside the image that implements the class, but @private outside.
This is most useful for instance variables in framework classes, where @private may be too restrictive but @protected or @public too permissive.
By default, all unmarked instance variables are @protected. ( In C++, class is private; struct is public)

A directive applies to all the instance variables listed after it, up to the next directive or the end of the list.

Instance variables marked @private are only available to subclasses by calling public accessor methods, if they exist.

Normally, to get information stored in an instance variable, other objects must send a message requesting it. However, a public instance variable can be accessed anywhere as if it were a field in a C structure:

Worker *ceo = [[Worker alloc] init];
ceo->boss = nil;
Public instance variables should be avoided except in extraordinary cases.

2.4 Messages to self and super

Objective-C provides two terms that can be used within a method definition to refer to the object that performs the method ---selfand super.

As receivers, self/super differ principally in how they affect the messaging process:

  • self searches for the method implementation in the usual manner, starting in the dispatch table of thereceiving object's class.
  • super begins in the superclass of the class (that defines the method where super appears).

Difference-between-self-and-super: http://stackoverflow.com/questions/5673230/objective-c-difference-between-self-and-super

In both cases they are specifying where the search for a method should start, in the case ofself the starting point is determined dynamically, in thesuper case it is known at compile time.

2.4.1 Example

High/Mid/Low define three different versions of negotiate method. Mid defines a method called makeLastingPeace.


if makeLastingPeace use self:

- makeLastingPeace
{
    [self negotiate];
}

[HighObject makeLastingPeace];  //will use high's negotiate
[MidObject makeLastingPeace];   //will use Mid's negotiate
[LowObject makeLastingPeace];   //will use Low's negotiate 
if makeLastingPeace use super:

//makeLastingPeace is defined in Mid class, so the super class
//is High
- makeLastingPeace
{
    [super negotiate];
}

[HighObject makeLastingPeace];  //will use high's negotiate
[MidObject makeLastingPeace];   //will use high's negotiate
[LowObject makeLastingPeace];   //will use high's negotiate 

2.4.2 Using super

Messages to super allow method implementations to be distributed over more than one class.

Each class in the inheritance hierarchy can implement a method that does part of the job and passes the message on to super for the rest.

Each init method has responsibility for initializing the instance variables defined in its class. But before doing so, it sends an init message to super to have the classes it inherites from initialize their instance variables:

- (id)init
{
    if(self = [super init])
    {
        ...
    }
}

2.4.3 Redefining self

Super is only used to tell compiler where to begin search for the method to perform.

self is a variable name that can be used in any number of ways, even assigned a new value.

Inside an instance, self refers to the instance; but inside a class method, self refers to the class object.

// a bad example
+ (Rectangle *)rectangleOfColor: (NSColor * color)
{
    self = [[Rectangle alloc] init];    //bad
    [self setColor: color];
    return [self autorelease];
}
It's usually better to use a variable other than self to refer to an instance inside a class method:

// a good example
+ (id)rectangleOfColor: (NSColor * color)
{
    id newInstance = [[Rectangle alloc] init];    //good
    [newInstance setColor: color];
    return [newInstance autorelease];
}
In fact, rather than sending the allocmessage to the class in a class method, it's often better to send alloc to self. If the class is subclassed, and rectangleOfColor: message is received by a subclass, the instance returned will be the same type as the subclass:

// a good example
+ (id)rectangleOfColor: (NSColor * color)
{
    id newInstance = [[self alloc] init];    //good
    [newInstance setColor: color];
    return [newInstance autorelease];
}

<think>我们分析条件:`if (!download_diag_obj->numberOfConnections || download_diag_obj->numberOfConnections > download_diag_obj->downloadDiagnosticMaxConnections)` 这个条件由两个子条件通过逻辑或(OR)连接组成,判断的是连接数参数是否有效。 具体拆解: 1. `!download_diag_obj->numberOfConnections` - 含义:检查`numberOfConnections`是否为0(或假值)。在C语言中,数值为0时逻辑判断为假,取非则为真;非0为真,取非为假。 - 作用:判断连接数是否未设置(即为0)或者设置为0(因为0个连接没有意义)。 2. `download_diag_obj->numberOfConnections > download_diag_obj->downloadDiagnosticMaxConnections` - 含义:检查设置的连接数是否超过了最大允许连接数(`downloadDiagnosticMaxConnections`)。 因此,整个条件判断的是:如果连接数未设置(为0)或者设置的连接数超过了允许的最大值,则条件成立,进入错误处理分支。 在错误处理分支中: - 记录错误日志(TR143_ERROR) - 将配置中的连接数(`pCfg->num_of_conn`)设置为默认值(`download_diag_obj->X_TP_DownDefConns`) - 同时,修正源数据(`download_diag_obj->numberOfConnections`)为默认值,以确保后续使用的一致性。 如果条件不成立(即连接数有效,非0且不超过最大值),则直接使用设置的连接数。 所以,这个条件的作用是确保连接数在有效范围内(1到最大值之间),否则使用默认值并修正源数据。 §§相关问题§§ 1. 为什么在条件中要检查`numberOfConnections`为0(即`!download_diag_obj->numberOfConnections`)?在实际应用中,设置连接数为0可能表示什么? 2. 如果`downloadDiagnosticMaxConnections`的值被错误设置为0,这个条件判断会有什么后果? 3. 在错误处理分支中,为什么要同时修改配置结构体(`pCfg->num_of_conn`)和源数据对象(`download_diag_obj->numberOfConnections`)的值? 4. 这个条件判断是否考虑到了负数连接数的情况?如果传入负数会如何处理? 5. 在TR369模式下,同样的有效性判断使用了参数结构体`pParm`而非`download_diag_obj`,这是为什么? </think>以下是针对条件判断 `if (!download_diag_obj->numberOfConnections || download_diag_obj->numberOfConnections > download_diag_obj->downloadDiagnosticMaxConnections)` 的详细解析: ### 条件判断分析 该条件由两个子条件通过逻辑或(`||`)组合而成,用于验证连接数参数的有效性: #### 1. **第一子条件:`!download_diag_obj->numberOfConnections`** - **含义**:检测连接数是否为**无效值** - **具体判断**: - 当 `numberOfConnections` 等于 `0` 时成立(0 在布尔判断中为假,`!` 取反为真) - 当 `numberOfConnections` 为 `NULL` 时成立(指针类型的特殊判断) - **设计目的**: - 确保连接数配置不能为零(零连接无意义) - 防止未初始化的空指针导致程序崩溃 #### 2. **第二子条件:`numberOfConnections > downloadDiagnosticMaxConnections`** - **含义**:检测连接数是否**超过系统上限** - **具体判断**: - 当设置的连接数大于系统允许的最大连接数时成立 - **设计目的**: - 防止资源过载(如内存耗尽或网络拥塞) - 确保诊断测试在安全范围内运行 #### 3. **组合逻辑:逻辑或(`||`)** - **触发条件**:任意一个子条件成立即进入错误处理分支 - **错误处理内容**: ```c TR143_ERROR(...); // 记录错误日志 pCfg->num_of_conn = 默认值; // 使用默认连接数 download_diag_obj->numberOfConnections = 默认值; // 修正源数据 ``` ### 设计意图图解 ```mermaid graph TD A[连接数检查] --> B{是否为0/NULL?} A --> C{是否超过最大值?} B -->|是| D[判定无效] C -->|是| D D --> E[记录错误日志] E --> F[使用默认值] F --> G[修正源数据] B -->|否| H[有效] C -->|否| H H --> I[使用原值] ``` ### 典型应用场景 1. **新设备初始化**: - `numberOfConnections` 默认为0 - 触发条件一 → 使用默认值10 2. **错误配置**: - 管理员误设连接数=1000 - 系统上限=500 → 触发条件二 → 自动修正为默认值 3. **空指针防护**: - 内存分配失败导致指针为NULL - 触发条件一 → 避免程序崩溃
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值