美文网首页iOS初学之OC程序员iOS 开发
阅读Effective Object-C 2.0 笔记(四)

阅读Effective Object-C 2.0 笔记(四)

作者: iLeooooo | 来源:发表于2016-04-18 18:36 被阅读110次

还是要好好学习英文啊,笔者只能看中文版的,下载地址如下:
http://download.csdn.net/detail/m6830098/7977521
看书的时候还是困的不行不行的,今天不看书都困-

今天来学习学习本书的第四章。

第一条:通过委托与数据源协议进行对象之间的通信。"委托模式(Delegate pattern)"的编程设计模式来实现对象间的通信, 该模式的主旨是:定义一套接口,某对象若是想接受另一个对象的委托,则需遵从此接口。以便成为其"委托对象(delegate)"。此模式可以将数据与业务逻辑解耦。视图对象的属性中,可以包含负责数据与事件处理的对象,这两种对象分别称为"数据源(data source)"和"委托(delegate)"。

#import <Foundation/Foundation.h>

@class WWNetworkFetcher;
@protocol WWNetworkFetcherDelegate <NSObject>

@optional  //可选方法
- (void)networkFetcher:(WWNetworkFetcher *)fetcher didReceiveData:(NSData *)data;
- (void)networkFetcher:(WWNetworkFetcher *)fetcher didFailWithError:(NSError *)error;

@end

@interface WWDataModel : NSObject

@property (nonatomic, weak) id <WWNetworkFetcherDelegate> delegate;

@end

注意:这个属性需定义成weak,而非strong,因为两者之间必须为"非拥有关系"。
实现委托对象的办法是声明某个类遵从委托协议,然后把协议中想实现的那些方法在类里实现出来。实现代码:

#import "WWDataModel.h"

  @interface WWDataModel() <WWNetworkFetcherDelegate>

  @end

@implementation WWDataModel

- (void)networkFetcher:(WWNetworkFetcher *)fetcher didReceiveData:(NSData *)data
{
    // Handle data
}

- (void)networkFetcher:(WWNetworkFetcher *)fetcher didFailWithError:(NSError *)error
{
    // Handle error
}

@end

委托协议中的方法一般都是"可选的"(optional),因为扮演"受委托者"角色的这个对象未必关系其中的所以方法。

    NSData *data = /* data obtained from network */;
    if ([_delegate respondsToSelector:@selector(networkFetcher:didReceiveData:)]) {
        [_delegate networkFetcher:self didReceiveData:data];
    }

- (void)networkFetcher:(WWNetworkFetcher *)fetcher didReceiveData:(NSData *)data{ 
    if (fetcher == _myFetcherA) {
        // Handle data
     } else if (fetcher == _myFetcherB) {
       // Handle data
    }
}

第二条:将类的实现代码分散到便于管理的数个分类中。

#import <Foundation/Foundation.h>

@interface WWPerson : NSObject

@property  (nonatomic, copy, readonly) NSString *firstName;
@property  (nonatomic, copy, readonly) NSString *lastName;
@property  (nonatomic, strong, readonly) NSArray *friends;

- (id)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName;

/**
 *  Friendship methods
 */
- (void)addFriend:(WWPerson *)person;
- (void)removeFriend:(WWPerson *)person;
- (BOOL)isFriendsWith:(WWPerson *)person;

/**
 *  Works methods
 */
- (void)performDaysWork;
- (void)takeVacationFromWork;

/**
 *  Play methods
 */
- (void)goToTheCinema;
- (void)goToSportsGame;

@end

在分类中可以这么写:

#import <Foundation/Foundation.h>

@interface WWPerson : NSObject

@property  (nonatomic, copy, readonly) NSString *firstName;
@property  (nonatomic, copy, readonly) NSString *lastName;
@property  (nonatomic, strong, readonly) NSArray *friends;

- (id)initWithFirstName:(NSString *)firstName andLastName:(NSString   *)lastName;

@end

/**
 *  Friendship methods
 */
@interface WWPerson(Friendship)
- (void)addFriend:(WWPerson *)person;
- (void)removeFriend:(WWPerson *)person;
- (BOOL)isFriendsWith:(WWPerson *)person;
@end

/**
 *  Works methods
 */
@interface WWPerson(Work)
- (void)performDaysWork;
- (void)takeVacationFromWork;
@end

/**
 *  Play methods
 */
@interface WWPerson(Play)
- (void)goToTheCinema;
- (void)goToSportsGame;

 @end

也可以分多个类来实现,放在多个h和m文件中。

WWPerson + Friendship(.h/.m)
WWPerson + Work(.h/.m)
WWPerson + Play(.h/.m)

//WWPerson + Friendship.h
#import "WWPerson.h"
@interface WWPerson(Friendship)
- (void)addFriend:(WWPerson *)person;
- (void)removeFriend:(WWPerson *)person;
- (BOOL)isFriendsWith:(WWPerson *)person;
@end

 //WWPerson + Friendship.m
#import "WWPerson + Friendship.h"

@implementation WWPerson (Friendship)
@end

将代码打散到分类中有个好处就是便于调试:对于某个分类中的所有方法来说,方法名称都会出现在其符号中。

第三条:总是为第三方类的分类名称加前缀。分类机制通常用于向无源码的既有类中新增功能。这个特性非常强大,但是在使用时也容易忽略其中可能产生的问题:分类中的方法是直接添加在类里面,他们就好比这个类中的固有方法运行期系统会把分类中随时向的每个方法都加入类的方法列表中。如果类中本来就有这个方法,而分类又实现了一次,那么分类中的方法会覆盖原来的那一份实现代码。

要点:向第三方类中添加分类时,总应给其名称加上你专用的前缀(我的就用:LXW)
向第三方类中添加分类时,总应给其中的方法名加上你专用的前缀。

第四条:勿在分类中声明属性。属性是封装数据的方式。尽管从技术上,分类里也可以声明属性,但这种做法还是要尽量避免,因为除了在"class-continuation分类"之外,其他的分类都无法向类中新增实例变量,因此他们无法把实现属性所需的实例变量合成出来。

第五条:使用"class-continuation分类"隐藏实现细节。类中经常会包含一些无须对外公布的方法及实例变量。其实这些内容也可以对外公布,并写明其为私有,开发者不应依赖他们。OC动态消息系统的工作方式决定了其不可能实现真正的私有方法或私有实例变量。然而我们最好还是只把确实需要对外公布的内部分公开,此时"class-continuation分类"就能用了。"class-continuation分类"和普通的分类不同,他必须定义在其所接续的那个类的实现文件里。其重要之处在于,这是唯一能声明实例变量的分类,而且此类没有特定的实现文件,其中的方法都应该定义在类的主实现文件中、与其他分类不同,"class-continuation分类"没有名称。写法如下:

@interface WWPerson ()

//methods here

@end

编写Object-C++代码时,"class-continuation分类"也很重要。Object-C++是Object——C与C++的混合体,其代码可以使用这两种语音来编写。由于兼容性原因,游戏后端一般用C++来写。有时候使用的第三方库可能只有C++绑定,此时也必须要用C++来编码。如:

#import <Foundation/Foundation.h>

#include "SomeCppClass.h"

@interface WWClass : NSObject {
    @private
    SomeCppClass _cppClass;
}

@end

该类的实现文件可能叫做WWClass.mm,其中.mm扩展名表示编译器应该将次文件按Object-C++来编译。否则就无法正确的引入SomeCppClass.h了。然而名为SomeCppClass的这个C++类必须完全引入,所以只要包含WWClass.h的类都必须用Object-C++编译才行,这样最终会导致整个引用都要用Object-C++编译。我们可以直接用"class-continuation分类"解决这个问题,在WWCLass.mm文件中:

//WWCLass.mm
#import "WWClass.h"
#include "SomeCppClass.h"

@interface WWClass () {
    SomeCppClass _cppClass;
}
@end

@implementation WWClass 
@end

改写后,起头文件就没有C++代码了。代理也可以用这个方法解决问题。

要点:
1.通过"class-continuation分类"向类中新增实例变量。
2.如果某属性在主接口中声明为"只读",而类的内部又要用设置方法来修改此属性,那么就在"class-continuation分类"中将其扩展为"可读写"。
3.把私有方法的原型声明在"class-continuation分类"里面。
4.若想使类岁遵循的协议不为人所知,则可于"class-continuation分类"中声明。

第六条:通过协议提供匿名对象。协议可在某种程度上提供匿名类型。具体的对象类型可以淡化成遵从某协议的id类型,协议里规定了对象所应实现的方法。使用匿名对象来硬菜类型名称(或类名)。如果具体类型不重要,重要的是对象能够响应(定义在协议里的)特定方法,那么可以使用匿名对象来表示。

最后,本书一共7个章节,此为第四章节:协议与分类。

共勉!一步一个巴掌印。。。。。

相关文章

网友评论

    本文标题:阅读Effective Object-C 2.0 笔记(四)

    本文链接:https://www.haomeiwen.com/subject/incnlttx.html