在上班之余学习IOS已经有三个多月了,因为基础有些薄弱从OC的基本语法开始学习的,相继看了青柚子和红柚子的书,现在在看编程实战,趁这个机会好好的总结一下:
1.命名约定
对象类型和名称一致,以免混淆
-(void) setURL:(NSString *)URL;//错误的命名方法 //更改为 -(void)setURLString:(NSString *)string; -(void)setURL:(NSURL *)URL;
静态变量(包括作用域)以s开头,而全集变量采用g开头,在通常情况下应避免使用常量之外的全局变量:
static MYThing *sSharedInstance
常量在Cocoa和Core Foundation中以k开头,在Cocoa中则不是,建议文件作用域内的(静态)常量都以k开头:
static const NSUInteger kMaximumNumberOfRows=3; NSString *const MYSomethingHappenedNotification=@"SomethingHappeded";
方法参数名称通常要加一个冠词(a,an,the)(楼主注:貌似不是很常见啊),用这种方式对参数进行命名可以避免与方法中的局部变量和实例名称混淆
实例变量以下划线开头
类名以大写字母开头,方法名和变量名则应该以小写字母开头,所有类名,方法名都采用驼峰式大小写(即每个单词的首字母大小写)进行分隔,而不采用下划线
2.自动引用计数
ARC不是垃圾回收,它只是一种编译器优化,因此它不能处理循环引用的问题:
垃圾回收机制如果外部对象到对象A的引用链接中断,则对象A和对象B都会被销毁,但那时ARC中因为A,B的相互引用,其引用计数都大于1,因此在IOS开发中必须做好对强引用的管理
属性的关系有两种主要类型:strong和weak,相当于非ARC环境中的retain和assign,只要存在一个强引用对象就会一直存在,不会被销毁。而weak在引用的对象被销毁后,weak的引用会被自动置为nil,所以delegate的属性总是应该声明为weak。
3.属性
在头文件声明公有属性,.m文件中声明私有属性:
//MyClass.h @interface class: NSObject @property (nonatomic,readwrite,weak) id delegate; @property (noatomic,readonly,strong) NSString *readonlyString;
@end //MyClass.m @interface MyClass() @property (noatomic,readwrite,strong) NSString *readonlyString; @property (noatomic,strong) NSString *privateString;
@end
编译器会自动创建_delegate,_readonlyString,_privateString几个变量,不过只能再init,dealloc中调用这些实例变量
另外可以看到在.m文件中重新声明了一下readonlyString变量,为它增加了一个setter的私有方法
属性的修饰关键字:
1)原子性(atomic,nonatomic)
本意是指属性的存取器方法是线程安全的,并不保证整个对象是线程安全的。比如使用NSMutableArray声明一个stuff,使用
self.stuff和self.stuff=otherstuff(只涉及到存取),而采用objectAtIndex的方法访问数组的时候并不是线程安全的。
但是如果属性并不需要其他线程访问的时候,使用原子属性是一种极大的浪费,因此通常情况下采用的是nonatomic
2)读写属性(readwrite和readonly)
3)设置方法修饰的关键词(weak,strong,copy)
注意的是对于不可变类如NSString和NSArray使用copy修饰
属性是用来表示对象的状态的,getter方法必须没有任何外部副作用,执行速度要快,不应该有阻塞。
属性和私有实例变量,在@implementation中可以使用私有实例变量
如@implementation{
NSString *_name;
}
默认的存储类型是strong
4.存储器
使用的一些范围,或者说必须使用存取器而最好别用实例变量:
KVO(键值观察Key-Value Observing)
属性可被自动观察,那次修改一个属性的时候可以调用willChangeValueForKey:和didChangeValueForKey:方法。
副作用(楼主太菜不是很懂副作用)
类或者子类可能会在设置的方法中引用副作用。可能会有一些注册到NSUndoManager的通知或者事件,除非真的必要,否则这些事件都不应该被忽略。类似的,类或者子类可能会在获取方法中使用缓存,而直接访问实例变量则不会用到缓存。
锁
在多线程代码中直接使用实例变量会突破锁机制,不用多说后果了吧
不应该用存储器的地方:
存储器内部
dealloc方法
初始化方法:这里可以用_Value,而不应该用属性
5.分类和扩展
category个人认为是比较好用的。可以减少继承,向现有的类添加新的方法,类似C#中的扩展方法
分类用于以模块化的方式将一个大型类分解成多个易于维护的类。
分类的声明非常简单,跟接口有些相像,在类名后的小括号里写上分类名称即可:
@interface NSMutableString (Capitalize)
-(void) capitalize
@end
Capitalize为分类的名称。从技术上讲,分类中可以进行方法覆盖,但是不建议这么做,如果两个分类包含了同名的方法,无法预测哪个方法会被使用。
关于分类,合理的使用就是为现有类添加某些适用的方法。使用原先的类名+分类的名称作为新的头文件和实现文件的名字。
比如为NSDate增加一个MyExtensions的简单分类:
//NSDate+MyExtensions.h @interface NSDate(MyExtensions) -(NSTimeInterval) timeIntervalUntilNow; @end; //NSDate+MyExtensions.m @implementation NSDate(MyExtensions) -(NSTimeInterval) timeIntervalUntilNow{ return [self timeIntervalSinceNow]; } @end
如果只是添加几个少数使用的方法,比较好的方式就是把这些方法都放在该MyExtensions类中,但是需要权衡一下防止代码膨胀。
关联引用为分类添加数据
在分类中不能创建实例变量,但是可以创建关联引用,通过关联引用为任何对象添加键值数据。
由于在分类中不能合成属性,
比如声明
//person类,并为其增加一个分类 email @interface Person:NSObject @property (nonatomic,copy) NSString *name; @end; @implementation Person @end; //增加一个分类 #import <objc/runtime.h> @interface Person(emailAdress) @property (nonatomic,copy) NSString *emailAdress; @end; ///如果这么写,在引用或者复制的时候出现属性无法获取或者复制的错误 //因为在分类中无法合成属性 //@implementation Person(emailAdress) //@end; //正确的做法 @implementation Person(emailAdress) static char emailAdressKey; -(NSString *)emailAdress{ return objc_getAssociateObject(self,&emailAdressKey); } -(void) setEmailAdress:(NSString *)emailAdress{ objc_setAssociateObject(self,&emailAdressKey,emailAdress,OBJC_ASSOCIATE_COPY); } @end;
可以看到关联引用是基于key的内存地址,而不是键的值.
如果在警告面板或者警告的控件上附加一个相关对象,使用关联引用是非常好的一个形式.
objc_setAssociatedObject(<#id object#>, <#const void *key#>, <#id value#>, <#objc_AssociationPolicy policy#>)//(目标类实例,关联引用key,关联引用值
,复制、赋值、保留语义)
objc_getAssociatedObject(<#id object#>,<#const void *key#>)//(目标类实例,关联引用key)
#import "ViewController.h" #import <objc/runtime.h> @implementation ViewController static const char kRepresentedObject; - (IBAction)doSomething:(id)sender { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:nil delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; objc_setAssociatedObject(alert,&
kRepresentedObject, sender, OBJC_ASSOCIATION_RETAIN_NONATOMIC); [alert show]; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { UIButton*sender = objc_getAssociatedObject(alertView, &
kRepresentedObject); self.buttonLabel.text = [[sender titleLabel] text]; } @end
类扩展
看网上说可以算是category的一个匿名类,可以自由声明合成属性,但是声明的方法必须在implementation中实现
6.协议
声明一个协议
@protocol 名称 <NSObject>
@required
//必须实现的
@optional
//选择实现的
协议和类一样可以继承,协议总是继承<NSObject>,NSObject 被划分为一个类和一个协议
委托协议(delegate protocol)
第一个参数是委托对象,这样一个委托才能管理多个委托对象
创建协议后还需要一个属性来便于操作它
@property (nonatomic,weak) id<Mydelegate>delegate;