总结一下iOS中的一些自己遇到的的基本概念,遇到了新的再写进来,方便以后自己回忆。免得到处再去查阅资料,做重复的事情!
1.alloc/init 和 new的区别
- alloc/init 和 new在功能上几乎是一致的,分配内存并完成初始化。差别在于,采用new的方式只能采用默认的init方法完成初始化,采用alloc的方式可以用其他定制的初始化方法,更加灵活。比如说A类里面重写了init方法,但是外部如果不小心用new方法对其调用,那么这个init方法的重写就会显得没意义甚至会出现我们不想要的结果。所以通常不建议用new。
2.[NSArray array] 和 [[NSArray alloc] init]的区别,arrayWithObjects也是同理。
- 这两个方式都是建立一个空的Array,[NSArray array]不需要release,使用autoreleasepool机制来管理对象的释放。[[NSArray alloc] init]需要自己手动release。举个例子:
关于内存管理的,如下:在ARC开启的情况下,声明一个属性用weak修饰,然后在在一个方法里面分别用alloc init方法和array方法创建数组并赋值给属性,结果前者创建的数组不存在,后者存在,可以向里面添加元素,请问这是问什么,两种创建方法有何区别?
@property (weak, nonatomic) NSMutableArray *arr;
{
self.arr = [NSMutableArray alloc] init]; // 创建方式1:该方法会有警告,不能像数组中添加元素。
self.arr = [NSMutableArray array];// 创建方式2:该法没有警告,可以向数组中添加元素。
[self.mtArr addObject: object];
}
- 创建方式1,由于是weak弱引用,该对象在执行完初始化句代码后就被释放了。创建方式2使用autoreleasepool机制,会在所在函数块执行完之后才释放,所以其可以向数组中添加元素。
3.成员变量,实例变量,属性变量的区别
- 首先我们看看成员变量和实例变量的区别
@interface MyViewController :UIViewControlle
{
UIButton *yourButton;
int count;
id data;
}
定义在接口 @interface 括号里面的统称为”成员变量”,实例变量本质上就是成员变量,是成员变量中的一种,只是实例是针对类而言,除去int float ....等基本数据类型,其他类型的变量都叫做实例变量。
- 成员变量和属性变量的区别,参考这篇文章:http://url.cn/45HIzWI
4.@property,@dynamic与@synthesize的区别
- @property:在iOS5之后编译器从GCC转换为LLVM,@property声明的属性默认会生成一个_类型的成员变量,同时也会生成setter/getter方法。在iOS5之前,属性的正常写法需要 成员变量 + @property + @synthesize 成员变量三个步骤。如下:
@interface ViewController ()
{
// 1.声明成员变量
NSString *myString;
}
//2.在用@property
@property(nonatomic, copy) NSString *myString;
@end
@implementation ViewController
//3.最后在@implementation中用synthesize生成setter&getter方法
@synthesize myString;
@end
@synthesize:于是synthesize两个作用:一是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。二是可以指定与属性对应的实例变量(自定义Property所对应的实例变量), 例如@synthesize myString = xxx,这时实例变量就是xxx。
@synthesize自动生成setter方法和getter方法举例:
实现文件(.m)中
@synthesize count;
等效于在实现文件(.m)中实现2个方法。
- (int)count
{
return count;
}
-(void)setCount:(int)newCount
{
count = newCount;
}
@dynamic:@dynamic告诉编译器,属性的setter与getter方法由用户自己实现,不自动生成。
更详细的理解可以看看这篇文章 http://m.blog.csdn.net/article/details?id=51788565
5.点语法的由来和理解可以看这篇文章:http://www.cnblogs.com/mjios/archive/2013/04/08/3006577.html
6.有了自动合成属性实例变量之后,@synthesize还有哪些使用场景?
1)应用场景1: @Property声明的属性同时重写了getter和setter方法
ViewController.h
#import
@interface ViewController : UIViewController
@property(nonatomic,strong)NSMutableDictionary*myDic;
@end
---------------------------------------------
ViewController.m
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
//@synthesize myDic = _myDic;
- (void)viewDidLoad {
[super viewDidLoad];
}
-(NSMutableDictionary *)myDic{
return _myDic;
}
-(void)setMyDic:(NSMutableDictionary *)myDic{
_myDic = myDic;
}
这个时候会报错:“Use of undeclared identifier '_myDic'”,因为@property默认给该属性生成getter和setter方法,当getter和setter方法同时被重写时,则系统就不会自动生成getter和setter方法了,也不会自动帮你生成_myDic实例变量,所以不会识别。应加上 @synthesize myDic = _myDic;
2)应用场景2:重写了只读属性property的getter,由于是只读只有get方法,所以这种情况也和第一种情况差不多。这里就不举例子了
##上面两种@synthesize的应用场景,虽然解决了报错的问题,但是我觉得是不适合使用@synthesize的,为什么呢?
首先要看@synthesize是做什么的,他是帮你自动实现ivar(实例变量)和访问方法,而你已经完全重写了访问方法,此时@synthesize只是让他帮你实现了一个ivar,已经背离了它本身该做的事情,为何不直接自己声明一个ivar呢,同样只要一行代码,这样却更加自然一些。
所以分析到最后,如果想要完全接管@property,最好不要用@synthesize,但是当然你是可以使用@synthesize的,所以这也是@synthesize的一种情况,在这种情况下,@synthesize只有一个作用就是帮你生成ivar。
而且与@synthesize相对的@dynamic,就是让你动态的实现一个属性的访问方法和ivar,如果你想要完全接管其property,最好用@dynamic修饰property,虽然不是必要的,但是显示的声明可以让别人更容易看懂你的代码:你是自己实现的这个属性。
所以应用场景1该这样写:
ViewController.h
#import
@interface ViewController : UIViewController{
NSMutableDictionary* _myDic;
}
@property(nonatomic,strong)NSMutableDictionary*myDic;
@end
---------------------------------------------
ViewController.m
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
@dynamic myDic;//告诉别人set&get都是自己重写了的
- (void)viewDidLoad {
[super viewDidLoad];
}
-(NSMutableDictionary *)myDic{
return _myDic;
}
-(void)setMyDic:(NSMutableDictionary *)myDic{
_myDic = myDic;
}
- 应用场景2该这样写:
ViewController.h
#import
@interface ViewController : UIViewController{
NSMutableDictionary* _myDic;
}
@property(nonatomic,strong,readonly)NSMutableDictionary*myDic; //这时候外部不能调用set方法,只能子类或该类内部才能调用
@end
---------------------------------------------
ViewController.m
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
@dynamic myDic;//告诉别人set&get都是自己重写了的
- (void)viewDidLoad {
[super viewDidLoad];
}
-(NSMutableDictionary *)myDic{
return _myDic;
}
-(void)setMyDic:(NSMutableDictionary *)myDic{
_myDic = myDic;
}
3)应用场景3:@synthesize还可以用来自定义Property所对应的ivar的名称。例子如下:
#import
@interface ZZYObject : UIView
@property(nonatomic,strong)NSMutableDictionary*myDic;
@end
-----------------------------
#import "ZZYObject.h"
@interface ZZYObject()
@end
@implementation ZZYObject
@synthesize myDic = myDicssss;
-(NSMutableDictionary *)myDic{
return myDicssss;
}
-(void)setMyDic:(NSMutableDictionary *)myDic{
myDicssss = myDic;
}
@end
但这种方式也并不推荐,因为如果大家可能更多使用的是默认的方案,这样所有人写出的代码都更容易理解。这样更符合大家的代码习惯。
4)应用场景4:在protocol中声明属性
- 应用场景4:覆盖属性 参考:http://blog.csdn.net/jeffasd/article/details/50475608
- 首先看一个例子:ZZYObject2是ZZYObject1的字类,它们都有一个同样的属性myName,代码如下
类ZZYObject1的代码:
#import
@interface ZZYObject1 : NSObject
@property(nonatomic,copy)NSString* myName;
@end
------------------------------------------------------------------
#import "ZZYObject1.h"
@implementation ZZYObject1
-(void)setMyName:(NSString *)myName{
_myName = @"我是ZZYObject1的set 方法";
}
@end
类ZZYObject2的代码:
#import "ZZYObject1.h"
@interface ZZYObject2 : ZZYObject1
@property(nonatomic,copy)NSString* myName;
@end
------------------------------------------------------------------
#import "ZZYObject2.h"
@implementation ZZYObject2
@end
在ViewController调用代码如下:
#import "ViewController.h"
#import "ZZYObject2.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
ZZYObject2*z2 = [[ZZYObject2 alloc]init];
z2.myName = @"dsada";
NSLog(@"我set了ZZYObject2 %@",z2.myName);
}
- 我们发现:ZZYObject2中的
@property(nonatomic,copy)NSString* myName;
这句代码有警告:“ Auto property synthesis will not synthesize property 'myName'; it will be implemented by its superclass, use @dynamic to acknowledge intention”。上面打印的结果为:
2017-02-24 11:02:14.389732 FugaiShuXing[10620:3285829] 我是ZZYObject1的set 方法
上面打印的并不是我们想要的结果,上面走的是父类ZZYObject1的set方法。原来在子类覆盖父类的属性时,编译器不会为子类合成带下划线的实例变量以及setter和getter方法,则需要自己来实现这些东西,否则这个属性将由父类实现,也就是说如果子类没有手写set和get方法,声明的@property相当于没写。
我们在ZZYObject2实现文件的代码加上一句
@synthesize myName = _myName;
(或者用“@dynamic完全接管property的方式”也可以,当然正如上面的警告系统也是推荐的
@dynamic)就可以了。
注:@dynamic完全接管property的方式,可参考应用场景1或2更正后的写法
#import "ZZYObject2.h"
@implementation ZZYObject2
@synthesize myName = _myName;
@end
//打印出了我们想要的结果
2017-02-24 11:30:16.117927 FugaiShuXing[10696:3296638] 我set了ZZYObject2 dsada