iOS知识点

Effective Objective-C 2.0笔记(一)

2017-04-10  本文已影响38人  peaktan

Effective Objective-C读书笔记,记录书中的总结点,加入了一些例子,方便理解和后期回顾。

一、熟悉Objective-C

1、了解OC语言的起源

2、在类的头文件中尽量少引入其他头文件

.h
#import <Foundation/Foundation.h>
//向前声明
@class Car;
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSUInteger age;
@property (nonatomic, strong) Car *car;
@end
.m
#import "Person.h"
#import "Car.h"
@implementation Person
@end

3、多用字面量语法,少用与之等价的方法

字面量字符串
NSString *str = @"This is string";
字面量数值
NSNumber *intNumber = @1;
NSNumber *floatNumber = @2.5;
NSNumber *doubleNumber = @3.14159;
NSNumber *bollNumber = @YES;
NSNumber *charNumber = @'a';
字面量数组
NSArray *array = @[@"1`",@"2",@"3"];
字面量字典
NSDictionary *dic = @{@"one":@"1",@"two":@2};

4、多用类型常量,少用#define预处理指令

static const NSString *kObserverName = @"name";
//用const修饰之后,如果修改它,那么编译器就会报错。
//而static修饰符则意味着该变量仅在定义次变量的编译单元可见。
.h
//声明一个全局常量
extern NSString *const PersonStringConstant;
.m
//定义全局常量
NSString *const PersonStringConstant = @"";

5、用枚举表示状态、选项、状态码

/**
 网络请求类型枚举
 */
typedef NS_ENUM(NSInteger, NetworkMethod) {
    NetworkMethodGet,
    NetworkMethodPost,
    NetworkMethodPut,
    NetworkMethodDelete,
};
typedef NS_OPTIONS(NSUInteger, UIRemoteNotificationType) {
    UIRemoteNotificationTypeNone    = 0,
    UIRemoteNotificationTypeBadge   = 1 << 0,
    UIRemoteNotificationTypeSound   = 1 << 1,
    UIRemoteNotificationTypeAlert   = 1 << 2,
    UIRemoteNotificationTypeNewsstandContentAvailability = 1 << 3,
}
屏幕快照 2017-03-20 下午6.30.59.png

二、对象、消息、运行时

1、理解“属性”这一概念

import <Foundation/Foundation.h>

@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@end

如果像下面这样,那么这个Person的实例中的name属性值就可能会莫名其妙的被改了:
- ```
Person *p = [[Person alloc] init];
NSMutableString *newName = [[NSMutableString alloc] initWithFormat:@"gaofeng"];
p.name = newName;
NSLog(@"====== %@",p.name);// gaofeng
[newName appendString:@"tan"];
NSLog(@"====== %@",p.name);// gaofengtan 

这并不是我们想要的结果。

2、在对象内部尽量直接访问实例变量

 - (Car *)car {
    if (!_car) {
        _car = [Car new];
    }
    return _car;
}

若没有调用 “获取方法” 就直接访问实例变量,则会看到尚未设置好的car,所以说,如果使用懒加载技术,那么必须通过存取方法来访问其数据。

3、理解 “对象等同性(equality)” 这一概念

4、以 “类族模式” 隐藏实现细节

 #import <Foundation/Foundation.h>
 typedef NS_ENUM(NSUInteger, GFEmployeeType) {
    GFEmployeeTypeDeveloper,
    GFEmployeeTypeDesigner,
    GFEmployeeTypeFinance
 };
 //雇员基类
 @interface GFEmployee : NSObject
 @property (nonatomic, copy) NSString *name;
 @property (nonatomic, assign) NSUInteger salary;
 + (instancetype)employeeWithType:(GFEmployeeType)type;
 - (void)doADaysWork;
 @end

.m

 #import "GFEmployee.h"
 #import "GFEmployeeDeveloper.h"
 #import "GFEmployeeDesign.h"
 #import "GFEmployeeFinance.h"
 @implementation GFEmployee
 + (instancetype)employeeWithType:(GFEmployeeType)type {
    switch (type) {
        case GFEmployeeTypeDeveloper:
            return [GFEmployeeDeveloper new];
            break;
        case GFEmployeeTypeDesigner:
            return [GFEmployeeDesign new];
            break;
        case GFEmployeeTypeFinance:
            return [GFEmployeeFinance new];
            break;
     }
 }
 - (void)doADaysWork {
    // subclass implement this
 }
@end

使用

GFEmployee *employee = [GFEmployee employeeWithType:GFEmployeeTypeDeveloper];
[employee doADaysWork];
比如UIButton:UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];

5、在既有类中使用关联对象(Associated Object)存放自定义数据

//创建一个自定义UIBarButtonItem,点击方法直接通过一个block来回调
#import "UIBarButtonItem+Common.h"
#import <objc/runtime.h>
static const void *BarButtonItemBlockKey = &BarButtonItemBlockKey;
@implementation UIBarButtonItem (Common)
 + (UIBarButtonItem *)itemWithBtnTitle:(NSString *)title clickHandle:(void (^)(void))action {
    UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] init];
    buttonItem.title = title;
    buttonItem.target = buttonItem;
    buttonItem.style = UIBarButtonItemStylePlain;
    buttonItem.action = @selector(handleClick:);
    [buttonItem setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor lightGrayColor]} forState:UIControlStateDisabled];
    //给buttonItem添加关联对象
    objc_setAssociatedObject(buttonItem, BarButtonItemBlockKey, action, OBJC_ASSOCIATION_COPY_NONATOMIC);
    return buttonItem;
}
 - (void)handleClick:(UIBarButtonItem *)buttonItem {
    //获取buttomItem对应key的关联对象
    void (^block)(void) = objc_getAssociatedObject(buttonItem, BarButtonItemBlockKey);
    block();
}
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,  // assign
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,   // nonatomic, retain
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,  // nonatomic, copy
    OBJC_ASSOCIATION_RETAIN = 01401,   // retain
    OBJC_ASSOCIATION_COPY = 01403  // copy
};

6、理解 objc_msgSend 的作用(消息传递机制)

// 发送消息最终会转变为调用函数,叫做 objc_msgSend,它的原型如下:
void objc_msgSend(id self, SEL _cmd, ...)

7、理解消息转发机制

 + (BOOL)resolveClassMethod:(SEL)sel
 + (BOOL)resolveInstanceMethod:(SEL)sel
 - (id)forwardingTargetForSelector:(SEL)aSelector
 - (void)forwardInvocation:(NSInvocation *)anInvocation

8、用 “方法调配技术(method swizzling)” 调试 “黑盒方法”

//获取方法
Method method = class_getClassMethod(Class cls, SEL name)
Method method = class_getInstanceMethod(Class cls, SEL name)
//交换方法
method_exchangeImplementations(Method m1, Method m2) 

9、理解 “类对象” 的用意

// 能够判断出对象是否为某个特定类的实例
isMemberOfClass:
// 能够判断出对象是否为某类或者其派生类的实例
isKindOfClass:
上一篇下一篇

猜你喜欢

热点阅读