大杂烩记录和@synthesize应用场景详解

总结一下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中声明属性

  1. 应用场景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

参考文章:http://blog.csdn.net/dp948080952/article/details/52611348 (如何正确使用@synthesize)

你可能感兴趣的:(大杂烩记录和@synthesize应用场景详解)