iOS - OC <<编写高质量iOS与OS X代码的多个有效方

2020-09-16  本文已影响0人  洧中苇_4187

Objective-C语言有Smalltalk演化而来,是消息型语言.

//Messaging (Objective-C)
Object *obj = [Object new];
[obj performWith:paramter1 and: paramter2];

//Function calling (C++)
Object *obj = new Object;
obj->perform(paramter1, paramter2);

区别

消息结构语言: 其运行时所执行的代码由运行环境决定.
函数调用语言: 由编译器决定.
调用多态:
1.函数通过虚方法表(virtual table)查找,到底该实行哪个函数;
2.消息结构语言是在运行时才会查找所需执行的方法,这个过程叫动态绑定(dynamic binding),Objective-C 都是由运行期组建(runtime component)来完成的.

1.在类的头文件中尽量少引入其他头文件

这样做的好处就是,能够缩短编译时间,所以当你引入一个类,而不需要知道这个类的细节(比如:用到这个类的某些属性/方法),只是声明它,则只需@class PersonClass

2.尽量多使用字面量语法,少用与之等价的方法
 NSArray *tmpArr = @[@1,@2,@"funking hard"];
    NSString *testStr = @"this is it";
    NSDictionary *tmpDic = @{
        @"last name" : @"Steve",
        @"hobtis" : @"see around",
        @"purpose" : @"making money"
    };
这样的好处是一目了然,
3.多用类型常量,少用#define 预处理指令
static const NSTimeInterval kAnimationDuration = 0.3;

3.1 >这样定义会确保常量值不变,不会无意中被人修改,从而导致应用程序各个部分所使用的值互不相同,因为试图修改都会编译器报错.
3.2 >常量的命名习惯,建议以k字母开头,用类名区分,后面紧接着使用说明,比如kPersonClassAnimationDuration,就能很清楚的知道这是所属于PersonClass这个类,用作动画时长的常量
3.3 >这样定义还可以标识类型,具有更多的参数信息.
3.4> 如果你想对外界暴露一个常值变量,又不想他知道具体的字符串,可以这样

//In the header file
extern NSString *const kEOCNotificationConstant;

//In the implementation file
NSString *const kEOCNotificationConstant = @"kEOCNotificationConstant";
4.用枚举表示状态,选项,状态码
enum EOCConnectionStateConnettionState : NSInteger {
    EOCConnectionStateConnettionState_before,
    EOCConnectionStateConnettionState_replace,
    EOCConnectionStateConnettionState_after
};

你可以指定用什么类型存储该枚举类型,这样系统能更好的分配空间(默认系统的值是从 0 开始分配,)

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};

这种枚举类型就可以进行 "或" 运算,

如果需要按位或操作来组合的枚举都应该使用 NS_OPTIONS来定义
不需要按位或 则 用enum ,NS_ENUM,(因为编译分为C++和非C++编译,底层会做判断,是否支持新枚举特性,即指派存储类型,所以在定义上会有差别)

枚举使用:
如果你指定了一个可选类型 NSComparisonResult,则前面要加上 typedef
typedef NS_ENUM(NSInteger, NSComparisonResult) {
    ...
};
 
 如果没有,就应该这样写...
NS_ENUM(NSInteger) {
    ...
};
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    switch (orientation) {
        case UIInterfaceOrientationUnknown:
        {
            NSLog(@"位置状态");
        }
        break;
        case UIInterfaceOrientationPortrait:
        {
           NSLog(@"竖屏状态");
        }
        break;
        case UIInterfaceOrientationPortraitUpsideDown:
        {
          NSLog(@"倒竖屏状态");
        }
        break;
        case UIInterfaceOrientationLandscapeLeft:
        case UIInterfaceOrientationLandscapeRight:
        {
         NSLog(@"左右状态");
        }
        break;
        //default:
        //break;
    }

在处理枚举类型的switch语句中,不要实现default分支,这样的话加入新枚举之后,编译器就会提示开发者:switch语句并未处理所有枚举

5. 属性的一些细节

应用程序二进制接口 (Application Binary Interface ABI),其中定义了生成代码时所赢遵循的规范.


图1
这是我看到所有对属性解释中,最清晰简洁的
//In header file 
@property (copy) NSString *firstName;
@property (copy) NSString *lastName;

//In implementation file
- (id) initWithFirstName:(NSString *)firstName
                         lastName:(NSString *)lastName;
{
      if ((self = [super init])) {
         _firstName = [firstName copy];
         _lastName = [lastName copy];
     }
     return self;
}

iOS开发相比于 Mac OS X开发,使用atomic通常不会有性能瓶颈.

在初始化方法 和 dealloc 中直接通过实例变量(_firstName)来获取;
内部对象读取时,直接_firstName,写入数据时,通过属性set赋值self.firstName = @"XXX"

6. 理解 "对象等同性" 这一概念
NSString *foo = @"test 123";
NSString *bar = [NSString stringWithFormat:@"test %i",123];
    
BOOL equalA = (foo == bar); 对比的是对象地址
BOOL equalB = [foo isEqual:bar];判断两个对象的地址是否相同,再判断类型是否一致, 然后再判断对象的具体内容是否一致
BOOL equalC = [foo isEqualToString:bar]; 首先两个对象必须为NSString类型,其次得相等.

NSLog(@"equalA:%zd equalB: %zd equalC: %zd",equalA,equalB,equalC);
//equalA:0 equalB: 1 equalC: 1

自定义判定等同性方法

//In header file
@interface ECOPerson : NSObject

@property(nonatomic,copy)NSString *firstName;
@property(nonatomic,copy)NSString *lastName;
@property(assign,nonatomic) NSUInteger age;

@end

//In implementation
- (BOOL)isEqual:(id)object
{
    if (self.class == [object class]) {
        return [self isEqualToPerson:object];
    } else {
        return [super isEqual:object];
    }
}

- (BOOL)isEqualToPerson:(ECOPerson *)otherPerson
{
    if (self == otherPerson) {
           return YES;
    }

    if (self.class != [otherPerson class]) {
       return NO;
    }

    if (![otherPerson.firstName isEqualToString:self.firstName]) {
       return NO;
    }

    if (![otherPerson.lastName isEqualToString:self.lastName]) {
       return NO;
    }

    if (otherPerson.age != self.age) {
       return NO;
    }

    return YES;
}

- (NSUInteger)hash
{
    NSUInteger fistNameHash = [_firstName hash];
    NSUInteger lastNameHash = [_lastName hash];
    NSUInteger ageHash = _age;

    return fistNameHash ^ lastNameHash ^ ageHash;
}

哈希值相等 不一定 两个对象相等,但两个对象相等,哈希值一定相等;
若想检测对象的等同性,请提供"isEqual" 与 "hash"方法
编写hash方法时,尽量使用计算速度快,哈希碰撞少的算法.

上一篇下一篇

猜你喜欢

热点阅读