Effective Objective-C 2.0 读书笔记—— 接口与API设计

Effective Objective-C 2.0 读书笔记 第 1 章 熟悉 Objective-C 第 2 章 对象消息运行时 第 3 章 接口和 API 设计 第 4 章 协议与分类 第 5 章 内存管理 循环引用 普通的两个变量互相引用 Block 循环引用 NSTimer 悬挂指针 持有释放不匹配 performselector CoreFoundation - Foundation try catch 其他 autoreleasepool blo 阅读详情

Effective Objective-C 2.0 读书笔记—— 接口与API设计

1. 用前缀避免命名空间冲突

正如书上所说OC没有其他语言之中内置的命名空间机制,所以我们在对方法进行命名时,就需要设法避免潜在的命名冲突。我们先了解一下命名空间冲突是什么东西。

假设有两个不同的库或模块,它们各自定义了一个名为 MyClass 的类:

// 第一个库
@interface MyClass : NSObject
// ...
@end

// 第二个库
@interface MyClass : NSObject
// ...
@end

当这两个库被同时引入同一个项目之中,那么编译器就会发现MyClass的定义重复,进而导致编译阶段发生错误。

那么避免这个问题的唯一办法就是变相实现命名空间,Apple宣称其保留使用所有 “两字母前缀” (two-letter prefix)的权利,所以一般来说我们自己写的类的前缀为三个字母。假设你所在的公司叫做Effective Widgets,那么就可以在所有应用程序都会用到的那部分代码中使用EWS 作前缀。

不仅是类名,应用程序中的所有名称都应加前缀。如果要为既有类新增“分类” (category),那么一定要给“分类” 及“分类” 中的方法加上前缀。除了以上这些我们算是比较熟知的内容会产生冲突时,书中也说到了,那就是类的实现文件中所用的 纯C函数及全局变量。

假设我们在两个不同的源文件中都有一个名为 completion 的函数。它们可能都在各自的 .m 文件中定义,例如:

// EOCSoundPlayer.m
void completion(SystemSoundID ssID, void *clientData) {
    EOCSoundPlayer *player = (__bridge EOCSoundPlayer*)clientData;
    if ([player.delegate respondsToSelector:@selector(soundPlayerDidFinish:)]) {
        [player.delegate soundPlayerDidFinish:player];
    }
}

// AnotherFile.m
void completion(SystemSoundID ssID, void *clientData) {
    // 另一个处理
}

由于C语言函数并没有所谓类的归属关系,只要链接这两个文件,编译器就会发现两个相同的completion函数,符号相同所以不知道调用哪一个。

解决这个问题除了我们刚刚说到的使用命名空间,即添加前缀的方式来解决之外,也可以使用静态函数:

  • 如果某个函数只在单个文件中使用,你可以将该函数声明为 static,这样它的符号仅对当前源文件可见,其他文件无法访问它。
static void completion(SystemSoundID ssID, void *clientData) {
    // 仅对当前文件可见
}

另外,当我们在编写第三方库时,如果引用了其他第三方库,就要把其他的第三方库的前缀也进行修改,那一份
第 三方库代码都加上你自己的前缀。例如,Application 你准备发布的程序库叫做EOCLibrary,其中引 入 了 名 为 XYZLibrary的第三方库 , 那么就应该把XYZLibrary 中的所有名字都冠以 EOC。于是,应用程序就可以随意使用它自已直接引人的那个XYZLi br ary 库 了,而不必担心与EOCLibrary 里的这个XYZLibrary相冲突

image-20250202152943881

2.提供"全能初始化方法"

所有对象均要初始化。在初始化时,有些对象可能无须开发者向其提供额外信息, 不过一般来说还是要提供的。通常情况下,对象若不知道必要的信息,则无法完成其工作。我们把这种可为对象提供必要信息以便其能完成工作的初始化方法叫做“全能初始化方法” (designated initializer)

如果创建实例的方法不止一种,我们还是需要选中一个作为全能初始化方法,书中使用NSDate举例

- (id)init;
- (id)initWithString:(NSString *)string;
- (id)initWithTimeIntervalSinceNow:(NSTimeInterval)seconds;
- (id)initWithTimeInterval:(NSTimeInterval)seconds sinceDate:(NSDate *)refDate;
- (id)initWithTimeIntervalSinceReferenceDate:(NSTimeInterval)seconds;
- (id)initWithTimeIntervalSince1970:(NSTimeInterval)seconds;

在官方的文档所述的一样,在上面几个初始化方法中,initWithTimeInt ervalSinceRef erenceDate: 是全能初始化方法。也就是说,其余的初始化方法都要调用它。于是,只有在全 能初始化方法中,才会存储内部数据。这样的话,当底层数据存储机制改变时,只需修改此方法的代码就好,无须改动其他初始化方法。

编写一个表示矩形的类,- (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height;就作为全能初始方法

#import <Foundation/Foundation.h>

@interface Rectangle : NSObject

@property (nonatomic, assign) CGFloat width;
@property (nonatomic, assign) CGFloat height;

// 全能初始化方法
- (instancetype)init;
- (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height;
- (instancetype)initWithRect:(CGRect)rect;

@end

.m文件实现如下

#import "Rectangle.h"

@implementation Rectangle

// 默认初始化方法
- (instancetype)init {
    self = [super init];
    if (self) {
        return [self initWithWidth:5.0f andHeight :10.0f];
    }
}

// 通过宽度和高度初始化矩形——全能初始化方法
- (instancetype)initWithWidth:(CGFloat)width andHeight:(CGFloat)height {
    self = [super init];
    if (self) {
        _width = width;
        _height = height;
    }
    return self;
}

// 通过正方形的边长初始化矩形(宽度和高度相同)

// 通过CGRect初始化矩形
- (instancetype)initWithRect:(CGRect)rect {
    self = [super init];
    if (self) {
        return [self initWithWidth:rect.size.width andHeight :rect.size.height];
    }
    return self;
}

@end

我们首先定义了- (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height;的方法作为全能的初始化方法,然后就在剩下的初始化方法之中调用我们的全能初始化方法,当底层数据存储机制改变时,只需修改此 方法的代码就好,无须改动其他初始化方法。

接着我们写一个正方形的类

#import "EOCRectangle.h"
@interface EOCSquare : EOCRectangle
- (id) initWithDimension: (float) dimension; 
@end
@implementation EOCSquare
- (id) initWithDimension: (float) dimension (
return [super initWithWidth:dimension andHeight:dimension) ; }
@end

由于是继承于矩形类,我们在自定义正方形的初始化方法时,也要注意到我们也有可能调用父类的初始化方法,为了避免出现未知的问题,我们需要重写父类之中的- (instancetype)initWithWidth:(CGFloat)width andHeight:(CGFloat)height方法

- (id) initWithWidth: (float) width andHeight: (float) height { 
  float dimension = MAX (width, height) ;
	return [self initWithDimension:dimension] ;
}

有时我们不想覆写超类的全能初始化方法不想令 initWithWidth:andHeight: 方法以其两参数中较大者作边长来初始化EOCSquare对象,我们认为这是方法调用者自己犯了错误。在这种情况下,常用的办法是覆写超类的全能 初始化方法并 于其中抛出异常:

-(id) initWithWidth: (float)width andHeight: (float) height { 
  @throw [NSException exceptionWithName:NSInternalInconsistencyException reason: @"Must use initWithDimension: instead." userInfo:nil];
}

不过,在Objective-C程序中,只有当发生严重错误时,才应该抛出异常,所以,初始化方法抛出异常乃是不得已之举,表明实例真的没办法初始化了。

3.实现description方法

description方法在平时应用的很多,这里不做多做赘述,书中作者讲了几个小技巧

当一个类有许多属性需要被打印时,我们可以使用NSDictionary来实现进行打印,例如

- (NSString*)description {
    return [NSString stringWithFormat:@"<%@: %p, %@>", 
            [self class], // 类名
            self,          // 当前对象的内存地址
          	@{	@"title":  _title,
          			@"latitude":@(_latitude),
                @"longitude":@(_longitude)}
          	];
}

打印出来结果如下

location = <EOCLocation: 0x7f98f2e01d20, {
    latitude = "51.506";
    longitude = 0;
    title = London;
}>

4.尽量使用不可变对象

这个点我在通过CoreLocation Framework深入了解MVC架构之中有过了解,我们在设置一个类持有的属性时,需要注意到类外部尽量不能直接操作类之中的核心属性,举一个例子:

NSMutableSet *set = [NSMutableSet new] ;
NSMutableArray *arrayA = [@[@1, @2]mutableCopy];
[set addObject:arrayA];
NSLog(@"set = %@", set);
// Output: set = {((1,2)) }

我们知道NSMutableSet的性质,当我们加入一个一模一样的元素时,set 里仍然只有一个对象,因为刚才要加入的那个数组对象和set 中已有的数组对象相等,所以set 并不会改变。我向set添加一个数组B,出现以下结果

程序是通过创建时这个数组的哈希值来判断两者是否相同

NSMutableArray *arrayB = [@[@1, @2]mutableCopy];
[set addobject :arrayB];
NSLog (@"set = %@", set) ;
// Output: set = ( ( (1,2)) 

但是我们如果绕一个弯,那么情况又会变得不同

NSMutableArray*arrayC= [@[@1] mutableCopy];
[set addObject:arrayC];
NSLog (@"set = %@", set) ;
// Output: set = {((1), (1,2))}

我们改变arrayC的内容,令其和最早加入set 的那个数组相等

[arrayC addObject: @2];
NSLog (@"set = %@", set) ;
// Output: set = {((1,2), (1,2) )}

用这个例子举例说明,轻易的使得属性可以被修改,可能会产生未知的错误,而且不易于项目的维护。

那么我们要做的其实就是让这些属性在外部访问的时候是只读(readonly),就可以保证我们的类之中的数据都是互相协调的。

那在类中,我们可能需要对属性进行修改,那我们就在.m之中将属性重新命名为可读写,举个例子,在.h文件当中

@property (nonatomic, readonly) NSString *identifier;
@property (nonatomic, readonly) NSString *title;
@property (nonatomic, readonly) float latitude;
@property (nonatomic, readonly) float longitude;



这些属性在类的外部只能被访问而不能修改,那么在.m文件当中,我们再赋予这个属性可以读写

@interface EOCPointOfInterest ()

@property (nonatomic, copy, readwrite) NSString *identifier;
@property (nonatomic, copy, readwrite) NSString *title;
@property (nonatomic, assign, readwrite) float latitude;
@property (nonatomic, assign, readwrite) float longitude;

@end
  

虽说这样在一定程度上可以使得外部不能直接修改这些属性,但我们仍然能够使用KVC的相关方法来进行修改,由于KVC是通过直接在类中查找并修改属性,所以直接避免了调用类本身提供的API。

另外,当我们在类之中带有数组这一类collection的时候,一般来说,内部就是一个可以灵活添加的collection,而外部返回的时候他们的不可变版本,即内部collection的拷贝

再举书中的例子

#import <Foundation/Foundation.h>

@interface EOCPerson : NSObject

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

- (id)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName;
- (void)addFriend:(EOCPerson *)person;
- (void)removeFriend:(EOCPerson *)person;

@end


//.m文件
#import "EOCPerson.h"

@interface EOCPerson ()
@property (nonatomic, copy, readwrite) NSString *firstName;
@property (nonatomic, copy, readwrite) NSString *lastName;
@property (nonatomic, strong) NSMutableSet *internalFriends; // 内部持有的可变集合
@end

@implementation EOCPerson

- (NSSet *)friends {
    return [_internalFriends copy]; // 返回不可变的 friends 集合
}

- (void)addFriend:(EOCPerson *)person {
    [_internalFriends addObject:person]; // 添加好友
}

- (void)removeFriend:(EOCPerson *)person {
    [_internalFriends removeObject:person]; // 移除好友
}

- (id)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName {
    if ((self = [super init])) {
        _firstName = [firstName copy];  // 保证属性被赋值
        _lastName = [lastName copy];
        _internalFriends = [NSMutableSet new]; // 初始化朋友集合
    }
    return self;
}

@end

这个类通过 readonly 属性保证了 firstName 和 lastName 不能被外部修改,只能在初始化时被赋值。同时,朋友的集合通过 addFriend: 和 removeFriend: 方法进行管理,但外部只能访问不可变的 NSSet 类型的集合。这样可以保持封装性和安全性。

5.理解Objective -C错误模型

当前很多种编程语言都有“异常” (exception)机制,Objective-C也不例外。OC特有的 “ 自动引用计数 ”,在默认情况下不是 “ 异常安全的 ” (e x c e p t i o n s a f e )。具体来说,这意味着 : 如果抛出异常 ,那么本应在作用域未尾释放的对象现在却不会自动释放了。

如果想生成**“异常安全”**的代码,可以通过设置编译器的标志 -fobjc-arc-exceptions 来实现。

不过,这将引入一些额外的代码,即使在不抛出异常的情况下,这部分代码仍然会执行。因此,使用该选项需要权衡代码执行效率和异常处理的安全性。

在 Objective-C 中,异常机制主要用于处理极其严重的错误,而不是用于常规的错误处理。这与其他语言不同,Objective-C 没有类似于 abstract class 的概念来标识某个类为抽象类。因此,为了实现类似的功能,我们可以通过在父类的关键方法中抛出异常,来确保子类必须实现该方法。

例如,如果你有一个抽象基类,应该确保用户不能直接实例化这个类,而是通过子类来使用。如果有人错误地尝试直接使用这个基类并调用必须被子类重写的方法,你可以通过抛出异常来提醒开发者:

// 抽象基类方法
- (void)someMethod {
    @throw [NSException exceptionWithName:NSInvalidArgumentException
                                   reason:@"This method must be overridden by a subclass"
                                 userInfo:nil];
}

在上述例子中,someMethod 是一个抽象方法,应该在子类中实现。如果有人直接调用了这个基类的 someMethod,程序将抛出一个异常,说明该方法必须由子类来实现。

这种做法确保了以下几点:

  1. 强制继承:开发者如果直接使用抽象基类而没有继承,程序会通过异常通知其错误。
  2. 提前捕获错误:通过抛出异常,你能够及时捕获潜在的设计错误,避免后续的逻辑错误。

需要注意的是,异常不应当用于普通的错误处理,因为抛出异常和捕获异常的过程比常规的条件判断更为昂贵和复杂。在生产代码中,异常应当仅用于严重的、无法恢复的错误情况。

在我们的实际应用之中,我们更多的是使用NSError来进行错误报告

NSError 是 Objective-C 中用于错误处理的标准类,它由以下三个核心部分组成:

  1. Error Domain(错误范围,类型:字符串)
    • 代表错误的发生范围,即产生错误的根源。
    • 通常使用特定的全局变量来定义,比如:
      • NSURLErrorDomain(表示 URL 处理相关的错误)。
      • NSCocoaErrorDomain(表示 Cocoa 框架内部的错误)。
    • 例如,当 URL 解析失败时,会使用 NSURLErrorDomain 来表示该错误来源于 URL 处理子系统。
  2. Error Code(错误码,类型:整数)
    • 用于指明在某个错误范围内发生的具体错误。
    • 同一错误范围内,可能有多个不同的错误情况,通常使用 enum 定义。
    • 例如,在NSURLErrorDomain下:
      • NSURLErrorNotConnectedToInternet(表示网络未连接)。
      • NSURLErrorTimedOut(表示请求超时)。
    • 在 HTTP 请求错误中,错误码可能会直接对应 HTTP 状态码,如 404(Not Found)、500(Internal Server Error)等。
  3. User Info(用户信息,类型:NSDictionary)
    • 存储有关错误的额外信息,便于调试和错误处理。
    • 常见的键值对:
      • NSLocalizedDescriptionKey:错误的本地化描述(例如:“请求超时”)。
      • NSUnderlyingErrorKey:表示导致当前错误的另一个错误,可用于构建“错误链”(Chain of Errors)。

NSError 的第一种常见用法是通过委托协议来传递此错误。有错误发生时,当前对象会把错误信息经由协议中的某个方法传给其委托对象 (delegate)。例如, NSURLConnection 在其委托协议NSURLConnectionDelegate 之中就定义了如下方法: - (void) connection: (NSURLConnection *) connection didFail WithError: (NSError *)error 。虽然 NSURLConnection 已被 NSURLSession 取代,但它仍然可以用于理解 委托模式下的错误传递。

#import <Foundation/Foundation.h>

@interface MyConnectionDelegate : NSObject <NSURLConnectionDelegate>
@end

@implementation MyConnectionDelegate

// 连接失败时回调此方法,并传递 NSError
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"网络请求失败,错误信息: %@", error.localizedDescription);
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 创建请求
        NSURL *url = [NSURL URLWithString:@"https://invalid.url"]; // 一个无效URL,强制产生错误
        NSURLRequest *request = [NSURLRequest requestWithURL:url];

        // 创建代理对象
        MyConnectionDelegate *delegate = [[MyConnectionDelegate alloc] init];

        // 使用 NSURLConnection 发送请求
        NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate];

        // 运行 RunLoop,以便异步回调能执行
        [[NSRunLoop currentRunLoop] run];
    }
    return 0;
}

还有另一种方法是经由方法的 “输出参数” 返回给调用者,

- (BOOL) doSomething: (NSError**)error
- (BOOL)doSomething:(NSError **)error {
    // 执行可能会出错的操作
    if (/* 发生错误 */) {
        if (error) {
            // 如果传入的 error 参数不为空,则通过 *error 传递错误
            *error = [NSError errorWithDomain:@"com.example.domain"
                                         code:1001
                                     userInfo:@{NSLocalizedDescriptionKey: @"发生了一个错误"}];
        }
        // 返回 NO,表示操作失败
        return NO;
    } else {
        // 返回 YES,表示操作成功
        return YES;
    }
}

对于错误码,我们可以自己设置枚举量,规范错误的类型。

(6)NUC980 SPI Nand 启动 方式一:下载到SPI-NAND-Flash中,这种方式可以将程序固化到SPIflash中,可以掉电保存。第二种方式下载到DDR中程序掉电丢失,但是DDR调试方便,时候调试的时候使用。之前的设置都是基于SD卡启动,今天测试一下是用SPI flash启动。方式二: 下载到DDR中,①设置为USB启动②下载到DDR中③运行。1:烧写BootLoader。 阅读详情

相关推荐

机器视觉/将HIK海康面阵相机连接Halcon软件

本文简述了如何将海康面阵相机连接到Halcon软件中进行实时取图的过程。

Dahe.qu 4866

《Effective Objective-C 2.0》读书笔记——接口与API设计

在构建应用程序时,可能会将其中的代码用在后续项目或供他人集成在别的项目,因此,很少有那种写完就不再复用的代码。编写接口时就会将其设计成易于复用的形式,这需要用到OC语言中常见的编程范式(paradigm),同时还需了解各种可能碰到的陷阱。

XY_Mckevince的博客 1011

计算机网络Wireshark实验(西安交通大学)

实验名称 计算机网络Wireshark实验 实验日期 2021 年 5 月 17 日 实验地点 XJTU

沉鱼叶的博客 1814

Effective Objective-C 2.0(52个有效方法) —— 接口与API设计 读书笔记

15、用前缀避免命名空间冲突 选择与你的公司、应用程序或二者皆有关联之名称作为类名的前缀,并在所有代码中均使用这一前缀,前缀字母应该大于2个字母(Apple 宣称其保留使用所有“两字母前缀”(two-letter-prefix)的权利) 若自己所开发的程序库中用到了第三方库,则应为其中的名称加上前缀; 16、提供“全能初始化方法” “全能初始化方法”可为对象提供必要信息以便其能完成工作...

heqiang2015的博客 412

全网最全 | Linux(Ubuntn)系统安装 | 硬盘挂载 | 用户创建 | 生信分析配置

昨天(2024年7月23日)我们分享了学生及科研人员电脑配置推荐 | 笔记本+外置显卡配置,性能足够支持完成你博士论文文本内容,那么今天我们就分享一文解决 | Linux(Ubuntn)系统安装 | 硬盘挂载 | 用户创建 | 生信分析配置的教程,我们使用一文来解决大家在做生信时遇到安装系统、配置环境的问题。在此文中,我们尽快可能给出一套全网最全的教程。目标是解决新手小白同学查资源的困惑和难题。但是,每个童鞋遇到的问题不一样,此教程也不可能把你遇到的每个问题都归纳在其中。我们也希望,

BioinfoDu 2260

WSL2安装(详细过程)

适用于 Linux 的 windows 子系统允许开发人员直接在 Windows 上运行 GNU/Linux 环境 -- 包括大多数命令行工具、实用程序和应用程序,无需修改,而无需传统虚拟机或dualbot设置的开销。

qq_43636384的博客 3万+

【Effective Objective-C 2.0读书笔记】第三章:接口和API设计

一旦你完成了一个应用,你可能会希望在以后的工程中重用部分代码。你也可能会发布一些代码以供其他人来使用。这意味着你需要使用Objective-C的范式和理解众多的陷阱。

freeWayWalker的专栏 922

2024最新版Anaconda Navigator安装使用指南

本文简要介绍如何下载安装Anaconda Navigator最新版,以及如何使用Python内核搭载来完成应用程序开发。

jackson_lingua的博客 1万+

Effective Objective-C 2.0 读书笔记——关联对象

暑假的任务是学习Effective Objective-C 2.0书上的相关内容,今天终于开始着手写读书笔记,希望能够在寒假多发两篇吧其实关联对象一定程度上是等同于在子类之中添加属性的,只是相对来说,使用关联对象会比写一个子类并且调用其中的方法更加节约资源一点,本质上其实就给我们提供了一个动态修改的空间,更加的灵活。

aa2002aa的博客 1836

Cesium功能集(十二):Cesium中流体仿真

【代码】Cesium功能集(十二):Cesium中流体仿真。

GIS肆月 600

152:vue+leaflet 判断一个点是否在一个电子围栏内

本文介绍了一个基于Vue+Leaflet的示例,演示如何判断点是否在电子围栏内。作者大剑师兰特(优快云知名博主)展示了使用polygon.getBounds().contains(latlng)方法检测点与多边形边界的关系。代码仅需80行,通过点击地图触发判断逻辑,结果显示提示信息。该技术可广泛应用于地理围栏、位置服务等场景,需要安装turf依赖。文章提供了完整源码和配置说明,适合GIS开发者学习参考。

大剑师兰特的GIS世界 755

Effective Objective-C 2.0 读书笔记——内存管理(下)

对象在经历其生命期后 ,最终会为系统所回收 ,这时就要执行dealloc方法了。在每个对象的生命期内,此方法仅执行一次,也就是当保留计数降为0的时候。在这个方法之中,主要就是释放对象所拥有的引用。比如CoreFoundation 对象就必须手工释放,因为它们是由纯C的API 所生成的。在dealloc方法中,通常还要做一件事,那就是把原来配置过的观测行为都清理掉。之前讲到通知传值就有说到,我们当不需要监听后就需要在dealloc函数当中将注册的通知中心进行销注。

aa2002aa的博客 1412

OAuth2.0集成SpringSecurity加JWT实现单点登录

单点登录(Single sign on),英文名称缩写SSO,SSO的意思就是在多系统的环境中,登录单方系统,就可以在不用再次登录的情况下访问相关受信任的系统。也就是说只要登录一次单体系统就可以

Nicky's blog 9026

Effective Objective-C 2.0 读书笔记——协议和分类

协议定义了一系列方法,遵从此协议的对象应该实现它们,我们可以用协议把自己所写的API 之中的实现细节隐藏起来,将返回的对象设计为遵从此协议的纯i d类型。这样做可行,但不太理想。其实就是不命名的分类,没有名字的分类自然没办法在其他地方被应用,这就引申出我们使用它的场景——我们在编程的过程之中只需要对外公布的那部分内容公开,那么不公开的就会被放在。由于我们在编写功能较多的类时,一般都会给每一个代码开辟一个分类,让他负责一部分的功能,但是我们在编写分类时,尽量不要在分类之中添加对应属性,所有的属性都应该在。

aa2002aa的博客 2334

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

iOS-Effective Objective-C 2.0 读书笔记(三)

第三章的内容主要是说接口和API设计相关的注意事项。比如说我们自己写的代码需要设计以便于代码复用时,应该注意的一些问题包括哪些。简单总结  有些注意事项实际上很简单,而且很常见,我觉得并不需要太长篇幅来解释说明大家也能理解,所以这里主要以归纳的形式列出。

来自星星的の松子的博客 761

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

读书笔记:Effective Objective-C

语法 2.在类的头文件中尽量少引入其他头文件 除非却有必要,否则不要引入头文件。一般来说,应在某个类的头文件中使用 @class 来提及别的类,并在实现文件中引入那些类的头文件。这样做可以尽量降低类之间的耦合。 有时无法使用向前声明,比如声明类遵循协议。这种情况可以将协议的声明移至“class-continuation 分类”。 3. 使用字面量语法而不是与之等价的方法 创建字符串、数值、数组、字典。 NSNumber *someNumber = @1; NSArray *animals = @[@

Kingyu Luk's Blog 1670

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Effective Objective-C 2.0读书笔记 Ⅱ

文章目录接口与API设计用前缀避免命名空间冲突提供"全能初始化方法"实现 description 方法尽量使用不可变对象 接口与API设计 用前缀避免命名空间冲突 1.选择公司,应用程序或二者皆有关联之名称作为类名的前缀,并在所有代码中均作为前缀 2。若自己开发的程序库中用到了第三方库,则应为其中的名称加上前缀 提供"全能初始化方法" 在类中提供一个全能初始化方法,其他初始化方法均应调用此方法...

weixin_44824650的博客 4345

《Effective Objective-C 2.0》读书笔记---第七章

前言: 虽说不使用系统框架也能编写OC代码,但几乎没人这么做,即便是NSObject这个标准的根类,也属于Foundation框架,而非语言本身。若不使用Foundation,就必须自己编写根类,同时还要自己来写collection、事件循环、以及其他会用到的类。 第47条:熟悉系统框架 用户升级操作系统后,你所开发的应用程序也可以使用最新版的

小T是我 1062

《Effective Objective-C 2.0》读书/实战笔记 二

##《Effective Objective-C 2.0》读书/实战笔记 二 第3章:接口与API设计

weixin_33908217的博客 516

编写高质量的iOS代码--Effective Objective-C 2.0 读书笔记

编写高质量的iOS代码--Effective Objective-C 2.0 读书笔记 这本书年初刷完,感觉不错,介绍了很多小点,都是平日不怎么关注的. 第1章 熟悉Objective-C

晓月的专栏 5984

Effective Objective-C读书笔记

第3章 接口与API设计第15条:用前缀避免命名空间冲突1.OC没有命名空间机制; 2.避免此问题的唯一方法是:为所有名称都加上适当前缀; 3.Apple宣称其保留使用所有“两字母前缀”的权利,所以你自己选用的前缀应该是三个字母; 4.不仅是类名,应用程序中的所有名称都应加前缀(包括纯C函数和全局变量)。第16条:提供“全能初始化方法”1.

奔向火星的博客 614

《Effective Objective-C 2.0编写高质量iOS与OS X代码的52个有效方法》读书笔记(下)

1.为避免在不经意间使用了无效对象,一般在release之后会清空指针,=nil; 2.通常利用弱引用或者“手动”解除引用的方式破坏循环引用。 3.ARC下,规定以alloc、new、copy、mutabelCopy开头方法,调用者要负责返回对象的释放;反之,返回的对象会自动释放,调用者要注意对返回值的保留。 4.属性设置的正确流程:保留新值,释放旧值,更新变量。 5.ARC下deallo

WoodBear的博客 713

《Effective Objective-C 2.0》1、熟悉Objective-C

该系列是《Effective Objective-C 2.0——编写高质量iOS与OS X代码的52个有效方法》的读书笔记。 第一条:了解Objective-C语言的起源 同C++类似,Objective-C也是C语言进行面相对象化的扩展。二者存在一个根本性的区别: C++是一种基于函数调用的语言,运行时执行的代码由编译器决定。某个对象试图调用哪一个函数将在编译过程中确定好。只有在实

Workshop of Wenjie.Yin 1168

【Effective Objective-C 2.0读书笔记】第七章:系统框架

第47条 熟悉系统框架 第48条 少使用for循环多使用块枚举BlockEnumeration 第49条 对需要自定义其内存管理语义的集合使用无缝桥接Toll-FreeBridging 第50条 构建缓存时选用NSCache而非NSDictionary 第51条 精简initialize和load方法的实现代码 第52条 谨记NSTimer会retain它的目标对象

freeWayWalker的专栏 3816

iOS之《Effective Objective-C 2.0》读书笔记(49)

第49条:对自定义其内存管理语义的collection使用它无缝桥接 1.“无缝桥接”的概念 2.三种转换方式 3.把NSArray转换为CFArray

雨花石的博客 641

记录Effective Objective C 2 0笔记目录

Effective Objective-C 这本书只要认真看了的都会明白里面的东西有多重要 目前正在看第二遍,顺便写下自己的读书笔记,起个记录和提醒的作用,内容主要是简单总结,很少有例子,如果不清楚的,强烈建议看原书。当然对于电子书爱好者,这里分享下电子书版本。 第一章 熟悉Objective-C OC是在C语言的基础上添加了面向对象特性 1、Objective-C的起源、本质 2、...

weixin_34255793的博客 106
上一篇: Effective Objective-C 2.0 读书笔记——类对象
下一篇: Effective Objective-C 2.0 读书笔记——协议和分类
小鹿撞出了脑震荡
博客等级 码龄3年 1107粉丝 97原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值