博客> 熟悉Objective-C
熟悉Objective-C
2小时前 评论:0 阅读:83 sunqiaoqiao
ios

1、了解Objective-C语言的起源

使用“消息结构”的面向对象的语言。使用消息结构的语言,其运行时所应执行的代码由运行环境决定,而使用“函数调用”的语言,则由编译器决定。 NSString someString = @"The String"; 此变量为指向NSString 的指针,所有的oc语言的对象占内存总是分配在“堆空间(heap space)”,而绝不会分配在栈(stack)上。如果再创建一个变量,令其指向同一地址,那么并不拷贝该对象,只是这两个变量会同时指向此对象。 例如 NSString someString = @"The String"; NSString *anotherString = someString; 只是在栈中分配了两块内存,每块内存的大小都能容下一枚指针,这两块内存的值一样,都是NSString实例的内存地址。 分配在堆中的内存必须直接管理,分配在栈上的用于保存变量的内存则会在其栈弹出时自动清理。 OC将堆内存管理抽象出来,不需要用malloc 及free来分配或释放对象所占内存,运行时把这部分工作抽象为一套内存管理架构,叫做“引用计数”

CGRect 是结构体,不是对象,创建对象还需要额外开销,比如说分配及释放堆内存等。

OC在运行时才会检查对象类型,接收到一条消息之后,究竟应执行什么代码,由运行时决定而非编译器决定。

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

OC使用头文件(header file) 和 实现文件(implementation file)来区隔代码。我们经常在头文件中引入其他头文件,这种方法可行,但不优雅,我在声明另一个类的变量的时候,并不需要知道他这个类的全部细节,我只要知道又一个类名叫这个名字就可以了。@class。这叫做“向前声明(forward declaring)”。如果过早引入头文件,就会一并引入所有内容,若此过程持续下去,则要引入许多根本用不到的内容,这会增加编译时间。

向前声明也解决了两个类互相饮用的问题。当解析一个头文件时,编译器会发现它引入了另外一个头文件,而在那个头文件中又回过头来引用第一个头文件,使用#import 而非 #include指令虽然不会导致死循环,但这意味着两个类里又一个无法被正确编译。

但有时候必须在头文件引入其他头文件,比如继承自某类,需要引入父类头文件。再比如你写的类遵从某个协议(protocol),那么该协议必须有完整定义,且不能使用向前声明,向前声明只能告诉编译器有某个协议,而此时编译器需要知道协议中定义的方法。

除非的确有必要,否则不要引入头文件,一般来说,应在某个类的头文件中使用向前声明来提及别的类,并在实现文件中引入那些类的头文件,这样可以尽量降低类之间的耦合。

有时无法使用向前声明,比如声明某个类遵循一项协议,这种情况尽量把“该类遵循某协议”的这条声明移至class-continuation分类中,如果不行,就把协议单独放在一个头文件中,然后将其引入。(but excuse me ,whats class-continuation -- who can tell me)

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

字面量语法 其实就是直接赋值,比如, NSString someString = @“someString”; NSNumber someNumber = @1; NSNumber intNumber = @1; NSNumber floatNumber = @2.5f; NSNumber doubleNumber = @3.1415926; NSNumber boolNumber = @YES; NSNumber charNumer = @'a'; NSArray arr = @[@"1",@"3"]; NSDictionary *dict = @{@"lkey1":@"value1,"@"key2":@"value2"};

id object1 = @"1"; id object2 = nil; id object3 = @"3"; NSArray *arr = [NSArray arrayWithObjects:object1,object2,object3, nil]; NSLog(@"%@",arr);

NSArray *anotherArr = @[object1,object2,object3]; NSLog(@"%@",anotherArr);

出现这两种情况,第一种无崩溃,打印结果是2017-06-05 15:23:46.779 TestY[5832:123006] ( 1 ) 第二种崩溃,试图插入空的对象就崩了。崩溃信息 Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[1]'

第一种容易丢数据,还不知道,还不如崩溃了去找,起码数据不会丢。所以多使用字面量语法。

ps

NSArray arr = @[@"1",@"2",@"3"]; NSMutableArr mutableArr = [arr mutableCopy];可修改了。

4、多用类型变量,少用#define预处理命令

define ANIMATION_DURATION 0.3

没有类型信息,并且引用该类的所有的kk 都变成了0.3,仅仅在本类中使用,可以这样写 static const NSTimeInterval kANIMATION_DURATION = 0.3; 这样包含类型信息,容易理解,若仅局限于实现文件,那么在前面加字母k,若在类之外可见,以类名为前缀。 若不打算公开某个常量,应该将其定义在使用该常量的实现文件里 变量名一定要同时使用static 和const 来声明,如果试图修改const修饰的变量会报错,这就避免了在别的类中误修改。而static 意味着该变量仅可在定义此变量的实现类里面可见,

有时候需要对外公开某个常量。比方说通知,需要使用字符串来表示此项通知的名字,而这个名字可以声明为一个外界可见的常量。 // in the header file extern NSString *const Constant;

//in the implementation file NSString *const Constant = @“notification”; .h声明,.m定义,不希望有人改变此常量。改变的时候会报错。

举个例子 ViewController.h @interface ViewController : UIViewController extern NSString *const Contant; @end

ViewController.m

  • (void)viewDidLoad { [super viewDidLoad]; [self testConst]; }
  • (void)testConst{

    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; btn.frame = CGRectMake(100, 100, 100, 40); btn.backgroundColor = [UIColor blueColor]; [btn setTitle:@"next" forState:UIControlStateNormal]; [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [btn addTarget:self action:@selector(btnClicked) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btn]; }

  • (void)btnClicked{ SecondViewController sev = [[SecondViewController alloc] init]; [self presentViewController:sev animated:YES completion:^{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:Contant object:nil]; }); }]; }

SecondViewController.m

import "SecondViewController.h"

import "ViewController.h"

@interface SecondViewController ()

@end

@implementation SecondViewController

  • (void)viewDidLoad { [super viewDidLoad];

    self.view.backgroundColor = [UIColor redColor];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(acceptNotification) name:Contant object:nil]; // Do any additional setup after loading the view. }

  • (void)acceptNotification{ [self dismissViewControllerAnimated:YES completion:nil]; }

这样定义优于#define预处理指令,可以确保常量值一直不变。

5、用枚举表示状态、选项、状态码 这个是从C过来的

第一层理解

enum EOCConnectionState{ EOCConnectionStateDisconnected, EOCConnectionStateConnecting, ECOConnectionStateConnected, }; 定义该枚举变量 enum EOCConnectionState state = EOCConnectionStateConnecting; 可以这样,typedef enum EOCConnectionState = EOCConnectionState; 就可以这样写了。EOCConnectionState state = ECOConnectionStateConnected;

可以指明用何种“底层数据类型”来保存枚举类型的变量,这样就可以使用向前声明了,若不指定,编译器不清楚底层数据类型的大小,就不知道分配多少空间。指定底层数据类型所用的语法是 enum EOCConnectionState :NSInteger {/..../};

收藏
0
sina weixin mail 回到顶部