前言
零、代码重构(前提是已经实现了基本功能)
1.把代码放在它最应该呆的地方(代码重构的原则)
1》使用类方法实现字典实例化模型 (模型,通常是plist文件,网络)
使用类方法实例化模型数组
//类方法可以快速实例化一个对象--把代码放在它最应该呆的地方
+ (instancetype) appInfoWithDictionary : (NSDictionary *) appDictionary;
//返回plist文件对应的模型数组 ,使用懒加载
+ (NSArray *)appList;
2》使用类方法实例化视图对象,并用数据模型装配视图内容
用类方法进行视图的实例化
+ (instancetype) appView;//使用类方法加载xib
+ (instancetype) appViewWithAppInfo:(KNAppInfo *) appInfo;//使用类方法加载xib,参数用于视图的数据装配
- 方法:
1》设定开发计划、步骤
2》“每一个步骤告一段落之后,我们要暂停,进行代码审核”,有针对性的重构(抽离重复代码,模型和视图各尽职责)
一、深复制&浅复制
1.深复制:
1) 内容拷贝,即源对象和副本指向的是不同的两个对象;源对象的引用计数器不变,副本的引用计算器为1;
2)指针拷贝,源对象和副本指向同一个对象;对象的引用计算器+1,相当于做了一次retain操作
二、掌握的知识点
1.UIView的常见属性和方法
UIButton的常见设置
设置按钮的文字字体 折叠原码
//设置按钮的文字字体,需要拿到按钮内部的label
btn.titleLabel.font = [UIFont systemFontOfSize:13];//
/**
常见的字体有:UIFont代表字体,常见创建方法有以下几个:
+ (UIFont *)systemFontOfSize:(CGFloat)fontSize; //系统默认字体
+ (UIFont *)boldSystemFontOfSize:(CGFloat)fontSize; //粗体
+ (UIFont *)italicSystemFontOfSize:(CGFloat)fontSize; //斜体
*/
2.九宫格计算方法
1)每一列的x值一样,x值由列号决定
2)每一行的y值一样,y值由行号决定
//搭建界面,九宫格(以View为单元,内含UILabel、UIButton、UIImageView,同行和同列的位置关系 center.x = x+ width*0.5)
//view 的封装,带有数据模型的构造器以便进行内部控件的数据装配 ;数据模型(plist-》字典-》模型)--自定义的Plist 通常放置于Supporting Files目录中
#define kAppViewWidth 80 //视图宽度
#define KAppViewHeight 90 //视图高度
#define kColumnCount 4 //每行的视图个数--总列数
#define kRowCount 5 // 每一列的视图个数--总行数
//水平间距
CGFloat marginX =(CGRectGetWidth(self.view.frame)- kColumnCount * kAppViewWidth)/(kColumnCount+1);
//垂直间距
CGFloat marginY = (CGRectGetHeight(self.view.frame)- kRowCount* KAppViewHeight)/(kRowCount+1);
for (int i=0; i<28; i++) {
//行号
int row = i/kColumnCount;
//列号
int column =i%kColumnCount;
//位置
CGFloat x=marginX+(marginX+kAppViewWidth)*column;//x值决定视图所在的列;
CGFloat y= marginY+(marginY+KAppViewHeight)*row; //y值决定视图所在的行
//创建视图
UIView *appView = [[UIView alloc]initWithFrame: CGRectMake(x, y, kAppViewWidth, KAppViewHeight)];
[appView setBackgroundColor:[UIColor redColor]];
//将子视图添加至父视图
[self.view addSubview:appView];
}
3.字典转模型
使用模型替代字典的好处:
- 使用字典的坏处
通常取出和修改数据字典的数据,都要通过编写“字符串类型”的key值-》编辑器IDE没有智能提示、手动写key容易写错,且此时IDE不会有任何的警告和报错。
字典的使用例子 折叠原码
dict[@"name"] = @"Jack";
NSString *name = dict[@"name"];
- 使用数据模型的好处
1)数据模型(专门用来存放数据的对象),使用数据模型表示数据更专业些
2)使用模型修改数据、读取数据均采用对象的属性,提高编写效率
- 字典转模型‘
1)字典转模型的过程,通常被封装在模型内部
2)模型应该提供一个“带有NSDictionary类型”参数的构造方法
- (instancetype)initWithDict:(NSDictionary*)dict;
+ (instancetype)xxxWithDict:(NSDictionary*)dict;
/**
instancetype 简介(instancetype 在类型表示上跟id一样(可以表示任何对象类型))
1.instancetype 只能使用于返回值类型,不能像id一样用于参数类型;但instancetype比id多的一个好处是:IDE会检查instancetype的真实类型 ,提前警告(Incompatible pointer types initializing 'NSString *' with an expression of type 'KNAppInfo *'),以避免使用ID造成开发中不必要的麻烦
2.Init方法应该遵循Apple生成代码模板的命名规则,返回类型应该使用instancetype而不是id。
当类构造方法被使用时,它应该返回类型是instancetype而不是id。这样确保编译器正确地推断结果类型。
*/
字典转模型的过程
[采用KVC(keyValueCoding)实现]
plist文件解析-》字典数组(NSDictionary)-》模型数组(AppInfo)
/使用字典实例化模型 -- 把代码放在它最应该呆的地方
/**
1.Init方法应该遵循Apple生成代码模板的命名规则,返回类型应该使用instancetype而不是id。
当类构造方法被使用时,它应该返回类型是instancetype而不是id。这样确保编译器正确地推断结果类型。
IDE提前报警:Incompatible pointer types initializing 'NSString *' with an expression of type 'KNAppInfo *
--避免运行时才报错。
2.关于instancetype的小结
1》instancetype 主要用于类方法实例化对象时,让编译器主动推动对象的实际类型,以避免使用ID,造成开发中不必要的麻烦
2》OC中,在IOS7之后主推instancetype
swift语言中,绝大数的类的实例化,也都不需要指定类型
C++的11版本中,也有类似的关键字auto类型--》所有的语言都致力于,使语言更容易使用
3》instancetype 只能使用于返回值类型,不能当参数适用
*/
- (instancetype) initWithDictionary:(NSDictionary *)appDictionary{
//self is object
self = [super init];
if (self) {//既然nil解析成NO,所以没有必要在条件语句比较。不要拿某样东西直接与YES比较,因为YES被定义为1
//init local vars 将plist文件的信息在此处进行字典转模型
//KVC (key value coding) 键值编码:是一种间接修改、读取对象属性的一种方法;KVC被称为cocoa的大招
[self setValuesForKeysWithDictionary:appDictionary];
}
return self;
}
//使用类方法实现“字典实例化模型”--地道的代码
+ (instancetype) appInfoWithDictionary:(NSDictionary *)appDictionary{
//self is class
return [[self alloc]initWithDictionary:appDictionary];//+ (instancetype)alloc Description Returns a new instance of the receiving class.
}
@end
使用KVC的注意事项:
1》plist文件中的键值名称必须与模型对象的属性名称一致
2》模型中的属性,可以不全部出现在plist文件中
4.xib的使用( 用于描述“某一块局部的”UI界面,在开发阶段面向开发者的是xib文件,当把应用装到iPhone时,xib文件会转成nib文件)
xib 在Xcode 4.0 之前是主要的图形界面搭建工具,现在,xib仍是主流的界面开发技术;适合于开发小块的自定义视图
xib 的加载方式
//方式一
NSArray *objs = [[NSBundle mainBundle] loadNibNamed:@"KNAppView" owner:nil options:nil];//这个方法会创建xib中的所有对象,并且将对象按顺序放到objs数组中
//方式二
UINib *nib = [UINib nibWithNibName:@"MJAppView" bundle:[NSBundle mainBundle]];//bundle参数可以为nil,默认就是main bundle
NSArray *objs = [nib instantiateWithOwner:nil options:nil];
xib与storyBoard的异同点‘
1)相同点:都是用于描述UI界面,使用InterfaceBuilder工具来编辑
2)不同点:xib是 轻量级的,用于描述局部的UI界面;storyBoard是重量级的,用来描述整个应用软件的多个界面,并能展示多个界面间的跳转关系。
5.自定义View(View的封装)
自定义视图,并于xib建立连线-》减少代码对xib视图层次的依赖性
1)若一个view的内部子控件比较多,通常会考虑自定义一个view-》把内部的子控件创建屏蔽起来,不让外界关心
2) 外界可以传入对应的模型数据给view,view拿到模型数据之后,进行“内部子控件的数据”装配
简单的MVC
controller: 负责资源的调度,任务分配
7、文档&模拟器的安装
1).xcode 模拟器的安装位置:/Applications/xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs
2).xcode 文档安装路径 /Users/devzkn/Library/Developer/xcode/DerivedData 、
/Applications/xcode.app/Contents/Developer/Documentation/DocSets
着重看的文档如下:
IOS Human Interface guideLines
View Controller Programming Guide for IOS( 视图控制器的角色,视图控制器的生命周期)
正文
案例简介
1.功能分析:以九宫格形式展示应用信息;点击下载按钮之后,做出相应操作
2.步骤分析:
1). 确定界面元素,要有什么内容
2).用代码搭建界面:加载引用信息,根据应用的个数创建对应的view
3).编写代码 :监听下载按钮的点击。即建立连线,实现基本功能,进行进行代码优化。
- 搭建九宫格的步骤
1)明确每一块用的是什么View;
2)明确每一个view之间的父子关系
3)先尝试逐个添加格子,最后考虑使用for循环进行搭建‘
4)加载app数据,根据数据数量来创建对应个数的格子
5)添加格子内部的子控件
6)给格子内部的子控件装配数据
常见错误
a basic type & a class 的声明方式--一个是存储在栈区,另一个是栈区存储着堆区的对象对应的指针
基础类型 在声明时不要在*号,因为它们存储在栈区
//Change this:
CGFloat *marginX =(self.view.bounds.size.width - kColumnCount * kAppViewWidth)/(kColumnCount+1);
//to
CGFloat *marginX =(self.view.bounds.size.width - kColumnCount * kAppViewWidth)/(kColumnCount+1);
//Get rid of the asterisk. CGFloat is not a class, it is a typedef for double (a basic type).
代码示例
KNAppInfo.m
模型的实现代码
//
// KNAppInfo.m
// 01-应用程序管理// Created by devzkn on 3/6/16.// Copyright © 2016 devzkn. All rights reserved.
#import "KNAppInfo.h"
@implementation KNAppInfo
/**
问题: 使用readonly修饰成员变量的话,将不会生产带下划线的成员变量 undeclared identifier '_image',
解决方法如下:@synthesize 合成指令 --主动指定属性使用的成员变量名称
*/
@synthesize image =_image;//@synthesize 中可以定义 与变量名不相同的getter和setter的命名,籍此来保护变量不会被不恰当的访问
/**
懒加载模型的图片对象属性
*/
- (UIImage *)image{
if (nil == _image) {//
_image = [UIImage imageNamed:self.icon] ;
}
return _image;
}
//使用字典实例化模型 -- 把代码放在它最应该呆的地方
/**
1.Init方法应该遵循Apple生成代码模板的命名规则,返回类型应该使用instancetype而不是id。
当类构造方法被使用时,它应该返回类型是instancetype而不是id。这样确保编译器正确地推断结果类型。
IDE提前报警:Incompatible pointer types initializing 'NSString *' with an expression of type 'KNAppInfo *
--避免运行时才报错。
2.关于instancetype的小结
1》instancetype 主要用于类方法实例化对象时,让编译器主动推动对象的实际类型,以避免使用ID,造成开发中不必要的麻烦
2》OC中,在IOS7之后主推instancetype
swift语言中,绝大数的类的实例化,也都不需要指定类型
C++的11版本中,也有类似的关键字auto类型--》所有的语言都致力于,使语言更容易使用
3》instancetype 只能使用于返回值类型,不能当参数适用
*/
- (instancetype) initWithDictionary:(NSDictionary *)appDictionary{
//self is object
self = [super init];
if (self) {//既然nil解析成NO,所以没有必要在条件语句比较。不要拿某样东西直接与YES比较,因为YES被定义为1
//init local vars 将plist文件的信息在此处进行字典转模型
//KVC (key value coding) 键值编码:是一种间接修改、读取对象属性的一种方法;KVC被称为cocoa的大招
[self setValuesForKeysWithDictionary:appDictionary];//本质上是调用 self setValue:<#(nullable id)#> forUndefinedKey:(nonnull NSString *)
}
return self;
}
//使用类方法实现“字典实例化模型”--地道的代码
+ (instancetype) appInfoWithDictionary:(NSDictionary *)appDictionary{
//self is class
return [[self alloc]initWithDictionary:appDictionary];//+ (instancetype)alloc Description Returns a new instance of the receiving class.
}
/**
返回plist的数据模型数组
*/
+ (NSArray *)appList{
//解析plist,得到字典数组
NSArray *tmpDictionaryArray= [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"app" ofType:@"plist"]];
//可变数组,用于临时存储模型数组
NSMutableArray *tmpAppInfoArray = [NSMutableArray array];
for (NSDictionary *dict in tmpDictionaryArray) {
[tmpAppInfoArray addObject:[self appInfoWithDictionary:dict]];
}
return tmpAppInfoArray;
}
@end
KNAppInfo.h
模型的头文件
//
// KNAppInfo.h
// 01-应用程序管理
//
// Created by devzkn on 3/6/16.
// Copyright © 2016 devzkn. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
//模型数据
@interface KNAppInfo : NSObject
/**
使用KVC的注意事项:
1》plist中的键名称必学与模型属性名称保持一致
2》模型中的属性可以不全部出现在plist中
*/
@property (nonatomic,copy) NSString *icon;//属性名称与plist文件的NSDictionary 的key保持一致,以便采用KVC(键值编码)
@property (nonatomic,copy) NSString *name;
/**
@property
1>生成getter、setter、带下划线的成员变量(纪录属性内容)
2>使用readonly修饰成员变量的话,将不会生产带下划线的成员变量 undeclared identifier '_image'
*/
@property (nonatomic,strong,readonly) UIImage *image;//存储字典对应的图片对象
/**
通常实现字典实例化模型,都实现了以下模型的实例化方法
*/
//使用字典实例化模型
- (instancetype) initWithDictionary :(NSDictionary *) appDictionary;
//类方法可以快速实例化一个对象--把代码放在它最应该呆的地方
+ (instancetype) appInfoWithDictionary : (NSDictionary *) appDictionary;
//返回plist文件对应的模型数组 ,使用懒加载
+ (NSArray *)appList;
@end
控制器的代码
//
// ViewController.m 01-应用程序管理
// Created by devzkn on 3/3/16.
// Copyright © 2016 devzkn. All rights reserved.
//
#import "ViewController.h"
#import "KNAppInfo.h"
#import "KNAppView.h"
#define kAppViewWidth 80 //视图宽度
#define KAppViewHeight 90 //视图高度
#define kColumnCount 3 //每行的视图个数--总列数
#define kRowCount 4 // 每一列的视图个数--总行数
#define kStartY 1 //为了适配埋伏笔
@interface ViewController ()
@property (nonatomic,strong) NSArray *appInfoList;
@end
@implementation ViewController
//懒加载appInfoList,主要用于装配视图的数据,与视图控制器ViewController 关系不大,可以进行抽离
- (NSArray *)appInfoList{
if (nil == _appInfoList) {
_appInfoList = [KNAppInfo appList];//获取plist的数据模型数组
}
return _appInfoList;
}
- (void)viewDidLoad {
[super viewDidLoad];
//搭建界面,九宫格(以View为单元,内含UILabel、UIButton、UIImageView,同行和同列的位置关系 center.x = x+ width*0.5)
//1.view 的封装,带有数据模型的构造器以便进行内部控件的数据装配 ;数据模型(plist-》字典-》模型)
//水平间距
CGFloat marginX =(CGRectGetWidth(self.view.frame)- kColumnCount * kAppViewWidth)/(kColumnCount+1);
//垂直间距
CGFloat marginY = (CGRectGetHeight(self.view.frame)- kRowCount* KAppViewHeight)/(kRowCount+1);
//用plist文件的数据装配xib 的控件
for (int i=0; i<self.appInfoList.count; i++) {
//行号
int row = i/kColumnCount;
//列号
int column =i%kColumnCount;
//位置
CGFloat x=marginX+(marginX+kAppViewWidth)*column;//x值决定视图所在的列;
CGFloat y=kStartY+marginY+(marginY+KAppViewHeight)*row; //y值决定视图所在的行
//实例化视图
KNAppView *appView = [KNAppView appViewWithAppInfo:self.appInfoList[i]];//使用类方法,进行加载xib,获取app view的同时,对appview 进行数据装配( 使用模型装配视图 --实现视图内部的细节)
//设置位置
[appView setFrame:CGRectMake(x, y, kAppViewWidth, KAppViewHeight)];
//将子视图添加至父视图
[self.view addSubview:appView];
}
}
@end
KNAppView.h
视图的头文件
//
// KNAppView.h
// 01-应用程序管理
//
// Created by devzkn on 3/8/16.
// Copyright © 2016 devzkn. All rights reserved.
//
#import <UIKit/UIKit.h>
@class KNAppInfo;
@interface KNAppView : UIView
//自定义视图的现实的数据来源于模型,即使用模型装配自定义视图的显示内容
@property (nonatomic,strong) KNAppInfo *appInfo;//视图对应的模型,是视图提供给外界的接口
+ (instancetype) appView;//使用类方法加载xib
+ (instancetype) appViewWithAppInfo:(KNAppInfo *) appInfo;//使用类方法加载xib,参数用于视图的数据装配
@end
视图的实现文件
//
// KNAppView.m
// 01-应用程序管理
//
// Created by devzkn on 3/8/16.
// Copyright © 2016 devzkn. All rights reserved.
//
#import "KNAppView.h"
#import "KNAppInfo.h"
@interface KNAppView ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UILabel *appLable;
@end
@implementation KNAppView
/**
使用类方法加载xib,并对视图进行数据装配
*/
+(instancetype)appViewWithAppInfo:(KNAppInfo *)appInfo {
KNAppView *appview = [self appView];//实例化视图
[appview setAppInfo:appInfo];//使用模型装配app view
return appview;//返回视图对象
}
/**
使用类方法进行加载xib 视图,即实例化视图
*/
+(instancetype)appView{
return [[[NSBundle mainBundle] loadNibNamed:@"KNAppView" owner:nil options:nil]lastObject];
}
//利用setter方法,实现视图的数据装配
- (void)setAppInfo:(KNAppInfo *)appInfo{
_appInfo = appInfo;
[self.appLable setText:_appInfo.name];
[self.imageView setImage:_appInfo.image];
}
//弹出对应的app‘name
- (IBAction) downloadBUttonSelector:(UIButton *)button{
//获取button对应的父视图的子控件label对应的text属性值
//添加一个UILabel到界面上
UILabel *appNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(100,500, 160, 40)];
[appNameLabel setText:self.appInfo.name];
[appNameLabel setTextAlignment:NSTextAlignmentCenter];
//RGB 0 表示黑色;1 表示白色 The grayscale value of the color object, specified as a value from 0.0 to 1.0. 参数二: alpha 表示通明度 The opacity value of the color object, specified as a value from 0.0 to 1.0.
[appNameLabel setBackgroundColor:[UIColor colorWithWhite:0.8 alpha:0.5]];
[appNameLabel setNumberOfLines:2];
[[self superview] addSubview:appNameLabel];
//禁用按钮
[button setEnabled:NO];
//首尾式动画:修改对象的属性,frame、bounds、alpha;但其不容易监听动画的完成时间、不容易实现动画的嵌套
// 初始透明度
[appNameLabel setAlpha:0.0];//完全透明
//^ 表示为block, 是一个预先准备好的代码块;可以当作参数传递,在需要的时候执行;块代码在oc中,使用非常普遍
//块动画
[UIView animateWithDuration:1.0f animations:^{
//修改对象的属性
[appNameLabel setAlpha:1.0];//动画内容
} completion:^(BOOL finished) {
//动画结束之后,删除控件
[UIView animateWithDuration:1.0f animations:^{
[appNameLabel setAlpha:0.0];
} completion:^(BOOL finished) {
[appNameLabel removeFromSuperview];
}];
}];
}
@end
开发小结:
1.确定开发思路-》搭建界面、编写代码-》九宫格的布局-》
字典装模型(模型数据的处理,plist文件的加载)
-》实现按钮的监听方法-》使用类方法加载xib,简化代码搭建界面-》自定义视图,使用数据模型装配视图内容
字典转模型 折叠原码
/** 通常实现字典实例化模型,都实现了以下模型的实例化方法*/
//使用字典实例化模型
- (instancetype) initWithDictionary :(NSDictionary *) appDictionary;
//类方法可以快速实例化一个对象--把代码放在它最应该呆的地方
+ (instancetype) appInfoWithDictionary : (NSDictionary *) appDictionary;
//返回plist文件对应的模型数组 ,使用懒加载
KVC的赋值 折叠原码
- (instancetype) initWithDictionary:(NSDictionary *)appDictionary{
//self is object
self = [super init];
if (self) {//既然nil解析成NO,所以没有必要在条件语句比较。不要拿某样东西直接与YES比较,因为YES被定义为1
//init local vars 将plist文件的信息在此处进行字典转模型
//KVC (key value coding) 键值编码:是一种间接修改、读取对象属性的一种方法;KVC被称为cocoa的大招
[self setValuesForKeysWithDictionary:appDictionary];//本质上是调用 self setValue:<#(nullable id)#> forUndefinedKey:(nonnull NSString *)
}
return self;
}
IDE Xcode的使用技巧
1.设置常用代码块{}的时候采用<#UIView#> 进行变量的占位
- (instancetype)init
{
self = [super init];
if (self) {
<#statements#>
// ...
}
return self;
}
内存分析(栈、堆的存储信息)
1。只读指针属性的分析
一、不可变属性的值,若存储的是指针,则该属性对应的对象成员是可变的--只读指针属性的地址值不可变,意味的指针和指向的对象间的关系不可变,但被指向的对象内容是可变的(指向关系不可变,指向对象的内容可变)
示例:1.UIButton 对象有UILabel 、UIImageView 属性,都是readonly,即这两者的属性存储的指针地址是只读的,不可修改--但只读的指针指向的对象的属性成员是可以修改的
2.修改UIButton的只读属性titleLabel指针对应的对象属性font(readonly表示titleLabel的指针指不可修改,但label的font可以修改)
[[downloadButton titleLabel] setFont: [UIFont systemFontOfSize:12]];
//设置UIButton的title的font,先获取UI Button的内部UILabel:@property (nullable,nonatomic,readonly,strong) UILabel *titleLabel NS_AVAILABLE_IOS(3_0);
//@property(nonatomic,strong) UIFont *font NS_DEPRECATED_IOS(2_0, 3_0) __TVOS_PROHIBITED;过时
Objective-C中的@property和@synthesize用法
代表“Objective-C”的标志,证明您正在使用Objective-C语言;
Objective-C语言关键词,@property与@synthesize配对使用。
@synthesize 中可以定义 与变量名不相同的getter和setter的命名,籍此来保护变量不会被不恰当的访问(主动指定属性使用的成员变量名称)
//声明文件// KNAppInfo.h
@property (nonatomic,strong,readonly) UIImage *image;//存储字典对应的图片对象
//实现文件
#import "KNAppInfo.h"
@implementation KNAppInfo
@synthesize image =_image;//@synthesize 中可以定义 与变量名不相同的getter和setter的命名,籍此来保护变量不会被不恰当的访问
/**
懒加载模型的图片对象属性
*/
- (UIImage *)image{
if (nil == _image) {//
_image = [UIImage imageNamed:self.icon] ;
}
return _image;
}
1.格式:
声明property的语法为:@property (参数1,参数2) 类型 名字;
1)其中参数主要分为三类:读写属性: (readwrite/readonly)\setter语意:(assign/retain/copy)\原子性: (atomicity/nonatomic)针对多线程问题
2)各参数意义如下:
readwrite: 产生setter\getter方法
readonly: 只产生简单的getter,没有setter。
assign: 默认类型,setter方法直接赋值,而不进行retain操作
retain: setter方法对参数进行release旧值,再retain新值。
copy: setter方法进行Copy操作,与retain一样
nonatomic: 禁止多线程,变量保护,提高性能
2.所有者属性
我们先来看看与所有权有关系的属性,关键字间的对应关系。
属性值关键字所有权
strong __strong 有
weak __weak 无
unsafe_unretained __unsafe_unretained 无
copy __strong 有
assign __unsafe_unretained 无
retain __strong 有
strong
该属性值对应 __strong 关键字,即该属性所声明的变量将成为对象的持有者。
weak
该属性对应 __weak 关键字,与 __weak 定义的变量一致,该属性所声明的变量将没有对象的所有权,并且当对象被破弃之后,对象将被自动赋值nil。
并且,delegate 和 Outlet 应该用 weak 属性来声明。同时,如上一回介绍的 iOS 5 之前的版本是没有 __weak 关键字的,所以 weak 属性是不能使用的。这种情况我们使用 unsafe_unretained。
unsafe_unretained
等效于__unsafe_unretaind关键字声明的变量;像上面说明的,iOS 5之前的系统用该属性代替 weak 来使用。
copy
与 strong 的区别是声明变量是拷贝对象的持有者。
assign
一般Scalar Varible用该属性声明,比如,int, BOOL。
retain
该属性与 strong 一致;只是可读性更强一些。
https://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html#//apple_ref/doc/uid/TP30001163-CH1-SW2
常用Xcode技巧,之前已经介绍过快捷键了
1.快速打开文件
快速打开(Open Quickly)命令在Xcode的File菜单中,当然,用快捷键Command+Shift+O会更方便一些。
2.显示项目导航器
在一个有很多文件和文件夹的大型项目中, 显示项目导航命令(Reveal in Project Navigator) 可以为你节省很多时间,这个命令可以在界面左侧的项目导航栏中显示当前文件,默认快捷是Command + Shift + J.
3.辅助编辑器
你可能对辅助编辑器已经很熟悉了。但很多开发者对其使用的却不够充分,它可以显示一个文件的副本或者同时在用户界面和视窗控制器里操作,这一点非常赞。
辅助编辑器有很多种用法,我经常用它来找出某个特定算法都在哪里出现和被怎样的调用过. 把光标移动到一个算法的主体,从辅助编辑器的顶部菜单中选择Callers就可以看到。
4.跳转到方法
在使用类或者结构时,我经常需要快速的跳转到类的某个特定方法。通过快捷键Control + 6 再输入算法的头几个字母就可以非常方便的做到这点。
5.浏览文档
不管你多有经验,说明文档总是开发者最好的朋友。按住Option键并点击你感兴趣的符号,就可以快速的打开Xcode的文档浏览器,在这里可以搜索某个特定类或者方法。
6.范围编辑
多光标是个很棒的并且每个高级的编辑器都该有的特性。Xcode的代码编辑也有这个功能,但很难找到并且难以使用。在Xcode中,该功能被称为范围编辑(Edit All in Scope,默认快捷键Ctrl+Command+E)。
将 光标移动到要编辑的符号,鼠标指针在字符上停留一两秒就会在字符右边出现一个小小的倒三角,点击那个三角并从菜单中选择Edit All in Scope,你也可以自己给这个命令设定一个快捷键。(修改方法: Preferences -> Key Bindings -> 搜索 “Edit all in scope”)
可惜的是,Xcode对多光标功能的实现不如 Atom 或者 Sublime Text 来的强大,据我所知,Xcode的多光标功能只对符号起作用。
7.谁是饭桶
把光标移动到出错的那一行,单击右键选择然后在菜单里选择Show Blame for Line,啊哦,是你干的么?
8.常用编辑快捷键
1)Command + Delete: 删除光标至行首的内容、Control + K: 删除光标至本段末的内容、Control + Y: 将刚刚用Control + K或Command + Delete删除的内容粘贴至光标所在之处
2)control-Option-Up: 切换.h和.m
3》control +i 自动对齐