UI类控件知识总结:
//setClipsToBounds 把超出父视图的部分裁剪掉
[_showView setClipsToBounds:YES];
//@2x 意思是高清图
[backImageView setImage:[UIImage imageNamed:@"bg@2x.jpg"]];
//componentsSeparatedByString 以制定的界限分割字符串 得出的结果是一个数组
NSString * yellowShowNum =[[[[imageName componentsSeparatedByString:@"."] objectAtIndex:0] componentsSeparatedByString:@"_"] objectAtIndex:1];
做动画动作的方法总结:
方法一:雪花下落的动画
// [UIView animateWithDuration:<#(NSTimeInterval)#> animations:^{
// <#code#>
// } completion:^(BOOL finished) {
// <#code#>
// }]
方法二:UIView
// [UIView beginAnimations:<#(NSString *)#> context:<#(void *)#>];
// [UIView setAnimationDuration:<#(NSTimeInterval)#>];
// [UIView setAnimationDelegate:<#(id)#>];
// [UIView setAnimationTransition:<#(UIViewAnimationTransition)#> forView:<#(UIView *)#> cache:<#(BOOL)#>];
// [UIView commitAnimations];
方法三:定时器
// [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(runAroundForSun) userInfo:nil repeats:YES];
//-(void)animationRun
//{
// CGAffineTransform transForm = CGAffineTransformRotate(self.transform, M_PI_2);
//
// [UIView beginAnimations:nil context:nil];
// [UIView setAnimationDuration:2.5];
// self.transform = transForm;
// [UIView commitAnimations];
//}
一.自定义类的知识点总结:
1.先弄清自己需要建的什么类,建的类的相关继承关系
2.了解所建类的相关方法和属性,结合自己的应用场合选择声明合适的方法和属性,并在自定义类文件中实现声明的方法.
3.清楚所建类与主文件之间的关系,并合理使用类的方法.
二.UIAlertView 警告提示窗
UIAlertView * alertView = [UIAlertView alloc]initWithTitle:<#(NSString *)#> message:<#(NSString *)#> delegate:<#(id)#> cancelButtonTitle:<#(NSString *)#> otherButtonTitles:<#(NSString *), ...#>, nil
[alertView show];
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
}
三.控件知识:
//我们创建XIB的时候会用到这个方法(开头的文件部分)
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
创建代理 代理的创建方法(简单)
@interface LoginViewController : UIViewController
@end
@implementation LoginViewController
1.创建一个新的AppDelegate 对象
UILabel * label1 = [[UILabel alloc] init];
2. 找唯一的一个对象的时候 不能alloc 因为这等于重新创建一个
//[UIApplication sharedApplication]
UIApplication * p = [UIApplication sharedApplication];
3.app为唯一的一个对象
AppDelegate * user = p.delegate;
[user.window setRootViewController:regist];
四.使用数组来表示UI控件参数的方法:
UIFont * font = [UIFont systemFontOfSize:25];
NSDictionary * atti = [NSDictionary dictionaryWithObjectsAndKeys: font ,NSFontAttributeName, nil];
fontsize = [title sizeWithAttributes:atti];
btn.titleLabel.font = [UIFont systemFontOfSize:15];
数据源方法:
1.用于控制显示多少区
2.用来控制每区有多少行
3.用来设置单元格的方法(一般采用单元格冲重用机制)
UITableView * mainTableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStylePlain];
[mainTableView setDataSource:self];
[mainTableView setDelegate:self];
[self.view addSubview:mainTableView];
//设置表头
UIImageView * headerImageView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"1.jpg"]] autorelease];
[headerImageView setFrame:CGRectMake(0, 0, 320, 100)];
[mainTableView setTableHeaderView:headerImageView];
#pragma mark 数据源方法
//设置多少区
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 3;
}
//设置每个区多少行
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 20;
}
-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 100;
}
//-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
//{
// if (section == 0)
// {
// return @"同学";
// }
// else if (section == 1)
// {
// return @"小同学";
// }
// else
// {
// return @"老同学";
// }
//}
//设置区头视图
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView * headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
if (section == 0)
{
[headerView setBackgroundColor:[UIColor redColor]];
}
else if (section == 1)
{
[headerView setBackgroundColor:[UIColor blueColor]];
}
else
{
[headerView setBackgroundColor:[UIColor orangeColor]];
}
return headerView;
}
//设置区头高度
-(float)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 50;
}
//设置区脚
-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
static NSString * Identifier = @"sectionFooter";
UITableViewHeaderFooterView * view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:Identifier];
if (view == nil)
{
view = [[[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:Identifier] autorelease];
}
[view.contentView setBackgroundColor:[UIColor blueColor]];
return view;
}
-(float)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 50;
}
//设置单元格
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *Identifier = @"cell";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:Identifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:Identifier];
}
//indexPath.row 行的索引
[cell.imageView setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%d",indexPath.row % 2]]];
[cell setSelectionStyle:UITableViewCellSelectionStyleDefault];
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
#pragma mark tableView 代理方法
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"我现在点击了第%d区,第%d行",indexPath.section,indexPath.row);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
//添加向右的小箭头
// [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
剪切圆角图片的代码
[_headerImageView setClipsToBounds:YES];
[_headerImageView setContentScaleFactor:15];
//设置分割线风格
[mainTableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
//设置分割线 颜色
[mainTableView setSeparatorColor:[UIColor redColor]];
//设置表头
[mainTableView setTableHeaderView:headerImageView];
//设置表尾
[mainTableView setTableFooterView:footerImageView];
// 返回有多少区
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 4;
}
//返回每一个区有多少行
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{}
//设置区头区尾
//-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
//{}
/设置行高
//-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
//{}
//设置单元格
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{}
oc中的三种集合
1.NSArray
2.NSDictionary
3.NSSet
数据字典的创建方法:
//第一种创建方式
NSDictionary * dic = [NSDictionary dictionaryWithObjectsAndKeys:@"name",@"xiaoli",@"age",@"18",@"sex",@"girl",@"like",@"wo", nil];
//第二种创建方式 键和值之间以:相连
NSDictionary * dic2 = @{@"age": @"18",@"name":@"xiaoming",@"sex":@"girl"};
//第三种创建方式
NSDictionary * dic3 = [NSDictionary dictionaryWithObjects:@[@"18",@"xiaoming",@"boy"] forKeys:@[@"age",@"name",@"like"]];
UIWebView的创建和参数设置方法:
1.创建一个包含网站URL的数组
NSArray *http = @[@"http://www.2345.com",@"http://www.baidu.com",@"http://www.sina.com",@"http://www.tianya.com",@"http://www.qvod.com",@"http://cf.qq.com/",@"http://www.tencent.com",@"http://www.sohu.com",@"http://www.kugou.com",@"http://www.yinyuetai.com"];
2.创建UIWebView并设置大小和相关的链接信息:
UIWebView * webView = [[UIWebView alloc]initWithFrame:CGRectMake(0, 90, Kwidth, 480-90)];
NSURL *url = [NSURL URLWithString:[http objectAtIndex:button.tag ]];
NSURLRequest *urlReq = [NSURLRequest requestWithURL:url];
[webView setScalesPageToFit:YES];
[self.view addSubview:webView];
[webView loadRequest:urlReq];
不可变数组
//第一种创建方式
NSArray * array = [NSArray array];
//第二种创建方式 创建的时候 直接添加一个元素
NSArray *array1 = [NSArray arrayWithObject:@"123"];
//第三种 添加多个元素 ,以nil标记结尾
NSArray *array2 = [NSArray arrayWithObjects:@"123",@"234",@"345", nil];
// 第四种 创建方式
NSArray *array4 = [[NSArray alloc] init];
//创建一个不可变数组
NSArray *array = [[NSArray alloc] init];
NSArray *array1 = [NSArray array];
//不可变数组 添加元素 每个元素之间,隔开 最后以nil结尾
NSArray *array3 = [NSArray arrayWithObjects:@"小狗",@"小鸭",@"小三", nil];
NSLog(@"count-----%d",array3.count);
//objectAtIndex 获取指定索引的元素
NSLog(@"-------%@",[array3 objectAtIndex:0]);
//indexOfObject 根据元素内容 或者相应的索引值
NSLog(@"------%d",[array3 indexOfObject:@"小鸭"]);
可变数组
//创建一个可变的数组
NSMutableArray * mutableArray = [NSMutableArray array];
NSMutableArray * mutable1 = [NSMutableArray arrayWithCapacity:0];
//增加元素
[mutableArray addObject:@"李晨"];
[mutableArray addObject:@"范冰冰"];
[mutableArray addObject:@"李新"];
[mutableArray addObject:@"凤姐"];
//增加元素到制定位置
[mutableArray insertObject:@"蜡笔小新" atIndex:0];
//移除最后一个元素
[mutableArray removeLastObject];
//移除制定索引的元素
[mutableArray removeObjectAtIndex:2];
//用特定元素来替换制定 位置的元素
[mutableArray replaceObjectAtIndex:0 withObject:@"章子怡"];
//添加另外一个数组中的所有元素到这个数组中
[mutableArray addObjectsFromArray:array3];
//移除所有的元素
[mutableArray removeAllObjects];
//数组循环
for (int i = 0 ; i < [array6 count]; i++)
{
// NSLog(@"---------%@",[array6 objectAtIndex:i]);
NSLog(@"=========%@",array6[i]);
}
//因为不确定数组里面的元素是什么类型 所以我们用一个id类型
从数组中选取一个元素
for (id image in array5)
{
NSLog(@"array5=========%@",image);
}
UIAlertView代理方法的创建方法
一.使用系统的代理方法:
实现代理方法有三步:
1.在接口添加代理
2.把alertView的代理设置为自己
3.实现alertView的代理方法
二.自定义的代理方法:
#import <UIKit/UIKit.h>
一 . 声明一个协议
//protocol 协议
//协议名称 一般情况下 我们习惯用类名+delegate
/*
步骤1.
@protocol MyAlertViewDelegate <NSObject>
-(void)alertView:(MyAlertView *)alertView;
@end
改为@protocol MyAlertViewDelegate ;
不该的话找不到MyAlertView这个类
步骤2.
在@interface和@end之后
@protocol MyAlertViewDelegate <NSObject>
-(void)alertView:(MyAlertView *)alertView;
@end
步骤3.
在@interface和@end之间
声明一个代理的属性
@property id <MyAlertViewDelegate> delegate;
*/
@protocol MyAlertViewDelegate ;
@interface MyAlertView : UIView<UIAlertViewDelegate>
//固定格式 id <MyAlertViewDelegate> XXX;
@property id <MyAlertViewDelegate> delegate;
@end
#pragma mark --------一定在@end之后写下面的代码块
@protocol MyAlertViewDelegate <NSObject>
//代理方法
-(void)alertView:(MyAlertView *)alertView;
@end
//1.在@interface上面写代理方法 系统告诉我们找不到MyAlertView,所以我们需要在@interface和@end之后再写这个代理方法
//2.在下面写 系统告诉我们重复声明了 所以我们需要把上面的代理声明改为@protocol MyAlertViewDelegate ;
//3.在@interface里面声明一个代理的属性
二 . 添加和使用自定义的代理
UIButton * cancelBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[cancelBtn setFrame:CGRectMake(10, 10, 50, 50)];
[cancelBtn setTitle:@"确定" forState:UIControlStateNormal]
;
[cancelBtn setBackgroundColor:[UIColor redColor]];
[cancelBtn addTarget:self action:@selector(clickBtn) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:cancelBtn];
}
return self;
}
//发信号
-(void)clickBtn
{
//响应代理方法格式
// 前面是属性代理 + 代理方法 + 参数
//把正在被点击的btn所在alertView传过去
//哪一个alertView被点击了 self 指的就是哪个alretView
[delegate alertView:self];
// if ([delegate respondsToSelector:@selector(alertView:)])
// {
// [delegate alertView:self];
// }
}
内存管理
1.机制问题
2.同步和异步
3.retainCount引用计数 并不绝对准确
4.对象所有权
5.局部释放和全局释放
alloc 创建的对象 引用计数+1
p 创建 是在内存中用alloc 分配了一块内存
可以使引用计数+1的特殊字 (alloc , new , retain , copy)
People * p = [[People alloc] init];
[p retain];
//释放对象 release 让引用计数减1
[p release];
//查看引用计数 retainCount 并不绝对准确
NSLog(@"retainCount====%d",p.retainCount);
//malloc: *** error for object 0x8f1ac20: pointer being freed was not allocated malloc分配的内存赋值给了一个已经被释放的指针(此指针已不存在
//EXC_BAD_ACCESS 访问了一个坏的地址
#pragma mark 对象所有权
/*
1.对象没有释放的话,不会崩
2.对象多次释放 会崩溃
*/
//没有所有权
People * p3 = [[People alloc] init]; // alloc +1
[p3 retain]; // + 1 = 2;
元素被其他的对象拥有的时候,会保留一份所有权,引用计数+1
People * p4 = p3;
NSLog(@"p4=======%d",[p4 retainCount]);
//有所有权
/*
获得所有权
引用计数+1
*/
People * p5 = [p3 retain];
NSLog(@"p5======%d",[p5 retainCount]);
对象创建的时候引用计数为1,添加到视图中的时候引用计数为2;
谁创建谁释放
内存管理原则
(一)原则
只要还有人在使用某个对象,那么这个对象就不会被回收;
只要你想使用这个对象,那么就应该让这个对象的引用计数器+1;
当你不想使用这个对象时,应该让对象的引用计数器-1;
(二)谁创建,谁release
(1)如果你通过alloc,new,copy来创建了一个对象,那么你就必须调用release或者autorelease方法
(2)不是你创建的就不用你去负责
(三)谁retain,谁release
只要你调用了retain,无论这个对象时如何生成的,你都要调用release
(四)总结
有始有终,有加就应该有减。曾经让某个对象计数器加1,就应该让其在最后-1.
一、基本原理
(一)为什么要进行内存管理。
由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,这时需要回收一些不需要再继续使用的内存空间,比如回收一些不再使用的对象和变量等。
管理范围:任何继承NSObject的对象,对其他的基本数据类型无效。
本质原因是因为对象和其他数据类型在系统中的存储空间不一样,其它局部变量主要存放于栈中,而对象存储于堆中,当代码块结束时这个代码块中涉及的所有局部变量会被回收,指向对象的指针也被回收,此时对象已经没有指针指向,但依然存在于内存中,造成内存泄露。
(二)对象的基本结构
每个OC对象都有自己的引用计数器,是一个整数表示对象被引用的次数,即现在有多少东西在使用这个对象。对象刚被创建时,默认计数器值为1,当计数器的值变为0时,则对象销毁。
在每个OC对象内部,都专门有4个字节的存储空间来存储引用计数器。
(三)引用计数器的作用
判断对象要不要回收的唯一依据就是计数器是否为0,若不为0则存在。
(四)操作
给对象发送消息,进行相应的计数器操作。
Retain消息:使计数器+1,改方法返回对象本身
Release消息:使计数器-1(并不代表释放对象)
retainCount消息:获得对象当前的引用计数器值
(五) 对象的销毁
当一个对象的引用计数器为0时,那么它将被销毁,其占用的内存被系统回收。
当对象被销毁时,系统会自动向对象发送一条dealloc消息,一般会重写dealloc方法,在这里释放相关的资源,dealloc就像是对象的“临终遗言”。一旦重写了dealloc方法就必须调用[super dealloc],并且放在代码块的最后调用(不能直接调用dealloc方法)。
一旦对象被回收了,那么他所占据的存储空间就不再可用,坚持使用会导致程序崩溃(野指针错误)。
二、相关概念和使用注意
野指针错误:访问了一块坏的内存(已经被回收的,不可用的内存)。
僵尸对象:所占内存已经被回收的对象,僵尸对象不能再被使用。(打开僵尸对象检测)
空指针:没有指向任何东西的指针(存储的东西是0,null,nil),给空指针发送消息不会报错
注意:不能使用[p retaion]让僵尸对象起死复生。
三、内存管理原则
(一)原则
只要还有人在使用某个对象,那么这个对象就不会被回收;
只要你想使用这个对象,那么就应该让这个对象的引用计数器+1;
当你不想使用这个对象时,应该让对象的引用计数器-1;
(二)谁创建,谁release
(1)如果你通过alloc,new,copy来创建了一个对象,那么你就必须调用release或者autorelease方法
(2)不是你创建的就不用你去负责
(三)谁retain,谁release
只要你调用了retain,无论这个对象时如何生成的,你都要调用release
(四)总结
有始有终,有加就应该有减。曾经让某个对象计数器加1,就应该让其在最后-1.
四、内存管理代码规范
(一)只要调用了alloc,就必须有release(autorelease)
(二)Set方法的代码规范
(1)基本数据类型:直接复制
-(void)setAge:(int)age
{
_age=age;
}
(2)OC对象类型
-(void)setCar:(Car *)car
{
//1.先判断是不是新传进来的对象
If(car!=_car)
{
//2 对旧对象做一次release
[_car release];//若没有旧对象,则没有影响
//3.对新对象做一次retain
_car=[car retain];
}
}
(三)dealloc方法的代码规范
(1)一定要[super dealloc],而且要放到最后
(2)对self(当前)所拥有的的其他对象做一次release操作
-(void)dealloc
{
[_car release];
[super dealloc];
}
五、@property的参数
(1)内存管理相关参数
Retain:对对象release旧值,retain新值(适用于OC对象类型)
Assign:直接赋值(默认,适用于非oc对象类型)
Copy:release旧值,copy新值
(2)是否要生成set方法(若为只读属性,则不生成)
Readonly:只读,只会生成getter的声明和实现
Readwrite:默认的,同时生成setter和getter的声明和实现
(3)多线程管理(苹果在一定程度上屏蔽了多线程操作)
Nonatomic:高性能,一般使用这个
Atomic:低性能
(4)Set和get方法的名称
修改set和get方法的名称,主要用于布尔类型。因为返回布尔类型的方法名一般以is开头,修改名称一般用在布尔类型中的getter。
@propery(setter=setAbc,getter=isRich) BOOL rich;
BOOL b=p.isRich;// 调用
六、内存管理中的循环引用问题以及解决
案例:每个人有一张身份证,每张身份证对应一个人,不能使用#import的方式相互包含,这就形成了循环引用。
新的关键字:@class 类名;——解决循环引用问题,提高性能
@class仅仅告诉编译器,在进行编译的时候把后面的名字作为一个类来处理。
(1)@class的作用:声明一个类,告诉编译器某个名称是一个类
(2)开发中引用一个类的规范
1)在.h文件中使用@class来声明类
2)在.m文件中真正要使用到的时候,使用#import来包含类中的所有东西
(3)两端循环引用的解决方法
一端使用retain,一端使用assign(使用assign的在dealloc中也不用再release)
七、Autorelease
(一)基本用法
(1)会将对象放到一个自动释放池中
(2)当自动释放池被销毁时,会对池子里的所有对象做一次release
(3)会返回对象本身
(4)调用完autorelease方法后,对象的计数器不受影响(销毁时影响)
(二)好处
(1)不需要再关心对象释放的时间
(2)不需要再关心什么时候调用release
(三)使用注意
(1)占用内存较大的对象,不要随便使用autorelease,应该使用release来精确控制
(2)占用内存较小的对象使用autorelease,没有太大的影响
(四)错误写法
(1)连续调用多次autorelease,释放池销毁时执行两次release(-1吗?)
(2)Alloc之后调用了autorelease,之后又调用了release。
(五)自动释放池
(1)在ios程序运行过程中,会创建无数个池子,这些池子都是以栈结构(先进后出)存在的。
(2)当一个对象调用autorelease时,会将这个对象放到位于栈顶的释放池中
(六)自动释放0池池的创建方式
(1)ios 5.0以前的创建方式
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
`````````````````
[pool release];//[pool drain];用于mac
(2)Ios5.0以后
@autoreleasepool
{//开始代表创建自动释放池
·······
}//结束代表销毁自动释放池
(七)Autorelease注意
(1)系统自带的方法中,如果不包含alloc new copy等,则这些方法返回的对象都是autorelease的,如[NSDate date];
(2)开发中经常会写一些类方法来快速创建一个autorelease对象,创建对象时不要直接使用类名,而是使用self
八、ARC内存管理机制
(一)ARC的判断准则:
只要没有强指针指向对象,对象就会被释放。
(二)指针分类:
(1)强指针:默认的情况下,所有的指针都是强指针,关键字strong
(2)弱指针:_ _weak关键字修饰的指针
声明一个弱指针如下:
_ _weak Person *p;
ARC中,只要弱指针指向的对象不在了,就直接把弱指针做清空操作。
_ _weak Person *p=[[Person alloc] init];//不合理,对象一创建出来就被释放掉,对象释放掉后,ARC把指针自动清零。
ARC中在property处不再使用retain,而是使用strong,在dealloc中不需要再[super dealloc]。
@property(nonatomic,strong)Dog *dog;// 意味着生成的成员变量_dog是一个强指针,相当于以前的retain。
如果换成是弱指针,则换成weak,不需要加_ _。
(三)ARC的特点总结:
(1)不允许调用release,retain,retainCount
(2)不允许重写dealloc,但是不允许调用[super dealloc]
(3)@property的参数:
Strong:相当于原来的retain(适用于OC对象类型),成员变量是强指针
Weak:相当于原来的assign,(适用于oc对象类型),成员变量是弱指针
Assign:适用于非OC对象类型(基础类型)
(四)补充
让程序兼容ARC和非ARC部分。转变为非ARC -fno-objc-arc 转变为ARC的, -f-objc-arc 。
ARC也需要考虑循环引用问题:一端使用retain,另一端使用assign。
提示:字符串是特殊的对象,但不需要使用release手动释放,这种字符串对象默认就是autorelease的,不用额外的去管内存。