- 浏览: 662595 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
lizaochengwen:
网络请求碰到的中文乱码使用encodeURL吧- (NSStr ...
iPhone开发/iPad开发 中文乱码问题 -
hhb19900618:
还是没弄懂怎么解决了中文乱码? 正确代码能重写贴出吗
iPhone开发/iPad开发 中文乱码问题 -
zhengjj_2009:
我的理解是讲ipa文件解压缩之后再重新打包,已经破坏了签名,所 ...
xcodebuild和xcrun实现自动打包iOS应用程序 -
zhengjj_2009:
我参考你的“ 从ipa格式的母包生成其它渠道包的shell脚本 ...
xcodebuild和xcrun实现自动打包iOS应用程序 -
同一片天空:
问题果然解决了
iOS 搭建 XMPP实现环境
首 先,从copy开始说,简而言之,copy的目的就是生成一个新的实例,然后把其成员都按原实例赋值。对于非指针型的成员,比如BOOL, int, float,这样的赋值可以直接进行。但是对于指针型的数据,比如Objc中用到的对象,就有Deep Copy和Shallow Copy的区别——这个和在C++中的基本上是一样的:是生成新的成员对象,或是指向同一成员对象。
了 解了这点以后,再看看Copy在Objetive-C中的实现方式。如果要调用一个对象的copy方法,这个对象必须遵循NSCopying的协议。这个 协议中规定了一个方法:- (id)copyWithZone:(NSZone *)zone;我们就是通过实现这个方法给对象提供拷贝的功能。对于很多现有类,如NSString,NSDictionary,。。。这个方法已经实 现。假设我们现在自定义了一个类,需要为这个类提供拷贝的功能,就需要自己来动手写CopyWithZone的方法:示例如下:
这个是自定义的类:
@interface Product : NSObject <NSCopying>
{
NSString *productName;
float price;
id delegate;
}
@end
然后我们需要在Product类中实现NSCopying中的copyWithZone方法:
- (id)copyWithZone:(NSZone *)zone
{
Product *copy = [[[self class] allocWithZone: zone]
initWithProductName:[self productName]
price:[self price]]; //注意这里,我们使用了class的allocWithZone的方法创建了一个拷贝,这里假定Product类中有一个 initWithProductName: price:的初始化方法。那么这样调用后就得到了一个Product的副本,而且name和price都已经设置好了
[copy setDelegate:[self delegate]]; //这里再设置delegate
return copy; //返回副本
}
那么这样,如果我们有一个product的实例, 假设为product1,然后调用Product *product2 = [product1 copy];
就会使用我们上面写的copyWithZone的方法创建一个product1的副本,然后赋值给product2。
这里再以上面方法中的成员delegate为例,解释一下deep copy和shallow copy:
在 copyWithZone方法中,我们得到了一个新的product实例,但是delegate是个对象,所以在副本中,我们可以选择创建一个新的 delegate对象(deep copy),或是指向同一个delegate(shallow copy)。这个就取决于Product类中的setDelegate:方法了。你可以选择在setDelegate的时候,copy,也可以让它们都指 向同一个对象(但是需要retain,原因可以自己思考一下),当然,简单assign在某种情况下也是可以的。
假设在Product类中有setDelegate:方法,或是有delegate的property:
- (void)setDelegate: (id)aDelegate
{
[delegate release];
delegate = [delegate copy];
}
这 样就是一个深拷贝了,因为使用了delegate的copy方法得到了一个delegate的副本。至于如何得到delegate的副本,就要看 delegate的copyWithZone方法的实现了,不在这个层面的考虑中。也就是说,copy总是一中“递归”的形式,从上到下,我们可以一层一 层的考虑。
- (void)setDelegate: (id)aDelegate
{
[delegate release];
delegate = [aDelegate retain];
}
这样操作后,delegate和aDelegate为同一对象,但是为了内存管理方面的要求,我们调用了retain来将reference count加了一。当然,如果不需要了,还可以直接赋值(assign):
- (void)setDelegate: (id)aDelegate
{
delegate = aDelegate
}
你可以把这个例子自己实现一下,然后用log打一打内存,这个结构就很明了了。
然后再说一下可变副本(mutable copy)和不可变副本(immutable copy):
可变和不可变的概念,我们之前通过NSDictionary和NSMutableDictionary的区别了解过。
一 般来说,如果我们的某个类需要区别对待这两个功能——同时提供创建可变副本和不可变副本的话,一般在NSCopying协议规定的方法 copyWithZone中返回不可变副本;而在NSMutableCopying的mutableCopyWithZone方法中返回可变副本。然后调 用对象的copy和mutableCopy方法来得到副本。
举个例子:
NSDictionary类已经遵循了NSCopying和NSMutableCopy的协议,也就是说我们可以调用它的copy和mutableCopy来得到不可变和可变的副本,程序如下:
NSDictionary *testDict = [[NSDictionary alloc]initWithObjectsAndKeys:@"hello", @"test",nil];
NSDictionary *destDict = [testDict copy];
NSLog(@"test Dict:%p,retain Count: %d\ndest Dict:%p, retain Count: %d",testDict,[testDict retainCount],destDict,[destDict retainCount]);
这个在我机器上的运行结果为:
test Dict:0x11f220, retain Count: 2
dest Dict:0x11f220,retain Count: 2
看 起来,两个dict指向了同一片内存区域,但是retainCount加了1。这点需要理解一下,因为我们使用NSCopying方法要返回一个不可变对 象。而且原来的testDict也是不可变的,那么这里的“副本”也就没多大意义了(这就如同使用字符串常量时,系统会为我们优化,声明了多个字符串,但 是都是常量,且内容相等,那么系统就只为我们申请一块空间,这个道理是一样的)。既然都不可变,那么指向同一个空间就可以了。这里的copy和 retain没什么区别。
我们使用copyWithZone的方法返回immutable的对象,而不管原来的是可变的或是不可变的。我们再看一下如下代码:
NSMutableDictionary *testDict = [[NSMutableDictionary alloc]initWithObjectsAndKeys:@"hello", @"test",nil];
NSMutableDictionary *destDict = [testDict copy];
NSLog(@"test Dict:%p,retain count:%d\ndest Dict:%p,retain count:%d",testDict,[testDict retainCount],destDict,[destDict retainCount]);
[destDict setObject:@"what" forKey:@"test2"];
NSMutableDictionary是可变的,该代码在我机器上运行的结果为:
test Dict:0x20dcc0,retain count:1
dest Dict:0x209120,retain count:1
*** -[NSCFDictionary setObject:forKey:]: mutating method sent to immutable object
可 以看到因为我们调用了可变对象的copy方法,这个不像之前的例子中一样,只是retain了一下。这里的test dict和dest Dict已经是两个对象了,但是,copyWithZone的方法返回的是不可变的对象,因此之后的setObject: forKey:方法会出现错误。
下面这样改一下就OK了。
NSMutableDictionary *testDict = [[NSMutableDictionary alloc]initWithObjectsAndKeys:@"hello", @"test",nil];
NSMutableDictionary *destDict = [testDict mutableCopy];
NSLog(@"test Dict:%p,retain count:%d\ndest Dict:%p,retain count:%d",testDict,[testDict retainCount],destDict,[destDict retainCount]);
[destDict setObject:@"what" forKey:@"test2"];
NSLog(@"destDict:%@",destDict);
运行结果为:
test Dict:0x123550,retain count:1
dest Dict:0x10a460,retain count:1
destDict:{
test = hello;
test2 = what;
因为我们使用了mutableCopy来得到了一个可变副本。
Note:对于系统提供的所有既支持NSCopying,又支持NSMutableCopying的类。
copy方法,得到的是不可变对象,不管以前的是可变还是不可变。
mutableCopy方法,得到的是可变对象,不管以前的是可变还是不可变。
原文地址:http://blog.csdn.net/qingqichiyu/article/details/6718233
了 解了这点以后,再看看Copy在Objetive-C中的实现方式。如果要调用一个对象的copy方法,这个对象必须遵循NSCopying的协议。这个 协议中规定了一个方法:- (id)copyWithZone:(NSZone *)zone;我们就是通过实现这个方法给对象提供拷贝的功能。对于很多现有类,如NSString,NSDictionary,。。。这个方法已经实 现。假设我们现在自定义了一个类,需要为这个类提供拷贝的功能,就需要自己来动手写CopyWithZone的方法:示例如下:
这个是自定义的类:
@interface Product : NSObject <NSCopying>
{
NSString *productName;
float price;
id delegate;
}
@end
然后我们需要在Product类中实现NSCopying中的copyWithZone方法:
- (id)copyWithZone:(NSZone *)zone
{
Product *copy = [[[self class] allocWithZone: zone]
initWithProductName:[self productName]
price:[self price]]; //注意这里,我们使用了class的allocWithZone的方法创建了一个拷贝,这里假定Product类中有一个 initWithProductName: price:的初始化方法。那么这样调用后就得到了一个Product的副本,而且name和price都已经设置好了
[copy setDelegate:[self delegate]]; //这里再设置delegate
return copy; //返回副本
}
那么这样,如果我们有一个product的实例, 假设为product1,然后调用Product *product2 = [product1 copy];
就会使用我们上面写的copyWithZone的方法创建一个product1的副本,然后赋值给product2。
这里再以上面方法中的成员delegate为例,解释一下deep copy和shallow copy:
在 copyWithZone方法中,我们得到了一个新的product实例,但是delegate是个对象,所以在副本中,我们可以选择创建一个新的 delegate对象(deep copy),或是指向同一个delegate(shallow copy)。这个就取决于Product类中的setDelegate:方法了。你可以选择在setDelegate的时候,copy,也可以让它们都指 向同一个对象(但是需要retain,原因可以自己思考一下),当然,简单assign在某种情况下也是可以的。
假设在Product类中有setDelegate:方法,或是有delegate的property:
- (void)setDelegate: (id)aDelegate
{
[delegate release];
delegate = [delegate copy];
}
这 样就是一个深拷贝了,因为使用了delegate的copy方法得到了一个delegate的副本。至于如何得到delegate的副本,就要看 delegate的copyWithZone方法的实现了,不在这个层面的考虑中。也就是说,copy总是一中“递归”的形式,从上到下,我们可以一层一 层的考虑。
- (void)setDelegate: (id)aDelegate
{
[delegate release];
delegate = [aDelegate retain];
}
这样操作后,delegate和aDelegate为同一对象,但是为了内存管理方面的要求,我们调用了retain来将reference count加了一。当然,如果不需要了,还可以直接赋值(assign):
- (void)setDelegate: (id)aDelegate
{
delegate = aDelegate
}
你可以把这个例子自己实现一下,然后用log打一打内存,这个结构就很明了了。
然后再说一下可变副本(mutable copy)和不可变副本(immutable copy):
可变和不可变的概念,我们之前通过NSDictionary和NSMutableDictionary的区别了解过。
一 般来说,如果我们的某个类需要区别对待这两个功能——同时提供创建可变副本和不可变副本的话,一般在NSCopying协议规定的方法 copyWithZone中返回不可变副本;而在NSMutableCopying的mutableCopyWithZone方法中返回可变副本。然后调 用对象的copy和mutableCopy方法来得到副本。
举个例子:
NSDictionary类已经遵循了NSCopying和NSMutableCopy的协议,也就是说我们可以调用它的copy和mutableCopy来得到不可变和可变的副本,程序如下:
NSDictionary *testDict = [[NSDictionary alloc]initWithObjectsAndKeys:@"hello", @"test",nil];
NSDictionary *destDict = [testDict copy];
NSLog(@"test Dict:%p,retain Count: %d\ndest Dict:%p, retain Count: %d",testDict,[testDict retainCount],destDict,[destDict retainCount]);
这个在我机器上的运行结果为:
test Dict:0x11f220, retain Count: 2
dest Dict:0x11f220,retain Count: 2
看 起来,两个dict指向了同一片内存区域,但是retainCount加了1。这点需要理解一下,因为我们使用NSCopying方法要返回一个不可变对 象。而且原来的testDict也是不可变的,那么这里的“副本”也就没多大意义了(这就如同使用字符串常量时,系统会为我们优化,声明了多个字符串,但 是都是常量,且内容相等,那么系统就只为我们申请一块空间,这个道理是一样的)。既然都不可变,那么指向同一个空间就可以了。这里的copy和 retain没什么区别。
我们使用copyWithZone的方法返回immutable的对象,而不管原来的是可变的或是不可变的。我们再看一下如下代码:
NSMutableDictionary *testDict = [[NSMutableDictionary alloc]initWithObjectsAndKeys:@"hello", @"test",nil];
NSMutableDictionary *destDict = [testDict copy];
NSLog(@"test Dict:%p,retain count:%d\ndest Dict:%p,retain count:%d",testDict,[testDict retainCount],destDict,[destDict retainCount]);
[destDict setObject:@"what" forKey:@"test2"];
NSMutableDictionary是可变的,该代码在我机器上运行的结果为:
test Dict:0x20dcc0,retain count:1
dest Dict:0x209120,retain count:1
*** -[NSCFDictionary setObject:forKey:]: mutating method sent to immutable object
可 以看到因为我们调用了可变对象的copy方法,这个不像之前的例子中一样,只是retain了一下。这里的test dict和dest Dict已经是两个对象了,但是,copyWithZone的方法返回的是不可变的对象,因此之后的setObject: forKey:方法会出现错误。
下面这样改一下就OK了。
NSMutableDictionary *testDict = [[NSMutableDictionary alloc]initWithObjectsAndKeys:@"hello", @"test",nil];
NSMutableDictionary *destDict = [testDict mutableCopy];
NSLog(@"test Dict:%p,retain count:%d\ndest Dict:%p,retain count:%d",testDict,[testDict retainCount],destDict,[destDict retainCount]);
[destDict setObject:@"what" forKey:@"test2"];
NSLog(@"destDict:%@",destDict);
运行结果为:
test Dict:0x123550,retain count:1
dest Dict:0x10a460,retain count:1
destDict:{
test = hello;
test2 = what;
因为我们使用了mutableCopy来得到了一个可变副本。
Note:对于系统提供的所有既支持NSCopying,又支持NSMutableCopying的类。
copy方法,得到的是不可变对象,不管以前的是可变还是不可变。
mutableCopy方法,得到的是可变对象,不管以前的是可变还是不可变。
原文地址:http://blog.csdn.net/qingqichiyu/article/details/6718233
发表评论
-
SOCK_STREAM和SOCK_DGRAM
2015-07-23 20:08 1655sock_stream 是有保障的(即能保证数据正确传送到 ... -
SOCKET bind INADDR_LOOPBACK和INADDR_ANY的区别
2015-07-23 19:49 2062今天写程序时候,服务器端启动了,然后客户端总是连接不上,con ... -
htons()
2015-07-23 19:26 589在C/C++写网络程序的时候,往往会遇到字节的网络顺序和主机顺 ... -
使用symbolicatecrash分析crash文件
2015-03-10 11:32 1189原文 http://www.cnblogs.com/ning ... -
程序设计中的计算复用(Computational Reuse)
2015-02-10 10:18 672从斐波那契数列说起 ... -
didReceiveMemoryWarning
2015-02-09 16:11 548IPhone下每个app可用的内存是被限制的,如果一个app使 ... -
iOS开发中怎么响应内存警告
2015-02-09 16:08 659好的应用应该在系统内存警告情况下释放一些可以重新创建的资源。在 ... -
ASIHTTPRequest多次重复请求的问题
2014-12-17 14:34 648在一个车票订购的项目中,点击一次订购,却生成了2次订单,通过抓 ... -
从 CloudKit 看 BaaS 服务的趋势
2014-09-26 11:51 731从 6 月份 WWDC 苹果发布 ... -
ios编程--AVCapture编程理解
2014-09-26 11:03 9430、媒体采集的几个东西。这里所需要明白的是,在这个流程中,这里 ... -
NSURLProtocol
2014-09-25 10:42 8261、http://nshipster.com/nsurlpro ... -
关于iOS8的extension插件
2014-09-25 10:41 1301关于iOS8的extension插件,有兴趣的同学可以参考一下 ... -
【转】ios app在itunesConnect里面的几种状态
2014-08-05 10:34 1155Waiting for Upload (Yellow) Ap ... -
[转]iOS Dev (45) iOS图标与切片处理工具Prepo
2014-02-07 17:02 1036iOS Dev (45) iOS图标与切片处理工具Prepo ... -
phoneGap开发IOS,JS调用IOS方法/phoneGap插件开发
2014-01-13 17:49 1248前沿 废话不说phoneGap是什么不多介绍,官方网站: h ... -
如何在IOS平台下搭建PhoneGap开发环境(PhoneGap2.5)
2014-01-13 15:23 754由于在下最近在做基于HTML5的跨平台移植,搭建环境的时候着实 ... -
xcode 4 制作静态库详解
2013-12-20 18:27 549最近在做Apple的IOS开发,有开发静态库的需求,本身IOS ... -
【翻译】ios教程-创建静态库
2013-12-20 18:19 3123作者:shede333 主页:htt ... -
封装自己的控件库:iPhone静态库的应用
2013-12-20 17:03 594由于iPhone 控件的极度匮乏和自定义组件在重用上的限制,在 ... -
iphone:使用NSFileManager取得目录下所有文件(遍历所有文件)
2013-11-18 17:56 877From:http://note.sdo.com/u/xiao ...
相关推荐
6. 写一个NSString类的实现 ... obj = [self allocWithZone: NSDefaultMallocZone()]; obj = [obj initWithCString: nullTerminatedCString encoding: encoding]; return AUTORELEASE(obj); }
_sharedInstance = [super allocWithZone:zone]; }); return _sharedInstance; } - (id)copyWithZone:(NSZone *)zone { return _sharedInstance; } @end ``` 在Swift中,实现单例的常见方式是使用`GCD`的`...
然而,仅仅这样还不够,为了防止其他对象通过`alloc-init`方式创建新的实例,我们需要重写`allocWithZone:`方法: ```objc - (instancetype)allocWithZone:(struct _NSZone *)zone { return [SingletonClass ...
为了保证单例,需要控制类的构造方式,例如在Objective-C中重写`allocWithZone:`方法。单例模式简化了资源的访问和管理,但需谨慎使用,避免过度依赖和不必要的全局状态。 5. **策略模式**: 策略模式允许在运行时...
sharedInstance = [[super allocWithZone:NULL] init]; } return sharedInstance; } - (id)init { self = [super init]; if (self) { // 初始化操作 } return self; } @end ``` 2) **ARC + GCD**: 在ARC...
这段代码首先通过`allocWithZone:`方法为新对象分配内存,然后调用`initWithCString:encoding:`初始化方法设置字符串内容,最后返回autorelease的对象,确保对象在不再使用时会被正确地释放。 2. `static` 关键字的...
Prototype *copy = [[Prototype allocWithZone:zone] init]; copy.name = [self.name copyWithZone:zone]; // 对name属性进行深复制 return copy; } @end ``` 在这个例子中,`Prototype`类实现了`NSCopying`协议...
3. `allocWithZone:`方法被重写,确保在尝试分配新实例时,如果单例已经存在,返回现有的单例,否则创建新的实例。 4. `copyWithZone:`、`retain`和`retainCount`方法也被重写,以确保单例不会被复制或释放,保持其...
2. **内部实现**:在内部,首先通过`allocWithZone:`分配内存来创建一个新的`NSString`实例,然后调用`initWithCString:encoding:`来设置该实例的值为传入的C字符串。最后通过`AUTORELEASE`确保在适当的时机释放这个...
+ (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [super allocWithZone:zone]; }); return sharedInstance; } ```...
obj = [self allocWithZone:NSDefaultMallocZone()]; obj = [obj initWIthCString:nullTerminatedCString encoding:encoding]; return [obj autorelease]; } ``` 解析: - `allocWithZone:`方法用于内存分配。 -...
- 重写 `allocWithZone:` 方法以确保始终使用 `sharedStore()` 来获取单例。 - 在初始化时添加五个随机条目到 `BNRItemStore` 中。 - **示例代码**: ```swift class BNRItemStore: NSObject { static let ...
MyObject *copy = [[self class] allocWithZone:zone]; copy.name = [self.name copyWithZone:zone]; return copy; } - (id)mutableCopyWithZone:(NSZone *)zone { return [self copyWithZone:zone]; } - ...
- 使用`+ (instancetype)allocWithZone:(nullable NSZone *)zone`创建AVAudioPlayer实例。 - 调用`- initWithContentsOfURL:error:`或`- initWithData:error:`方法加载音频文件。前者需要提供音频文件的URL,后者...
obj = [[NSObject allocWithZone]init]; NSObject类参考文档里记录第三种方法是因为历史原因遗留下来的,在当前的Objective C中已经不再使用,所以我们就不考虑这种方式了。下面让我们主要看一下前两种方式。 第...
- 特殊情况下使用`+ (instancetype)allocWithZone:(NSZone *)zone`等初始化方法。 4. **继承**: - 使用`<父类名>`在`@interface`声明时指定继承关系。 - 子类可以通过`super`关键字调用父类的方法或属性。 5. ...
MyPrototype *copy = [[MyPrototype allocWithZone:zone] init]; copy.name = [self.name copyWithZone:zone]; // 复制其他属性... return copy; } @end ``` 在Swift中,虽然没有直接的NSCopying协议,但是我们...
Chocolate *copy = [[Chocolate allocWithZone:zone] init]; copy.brand = [self.brand copy]; copy.flavor = [self.flavor copy]; return copy; } @end ``` 在上述代码中,`Chocolate`类遵循了`NSCopying`协议...
+(instancetype)allocWithZone:(struct _NSZone *)zone { return [self sharedInstance]; } @end ``` 在Swift中,单例的实现相对简洁: ```swift class Singleton { static let sharedInstance = Singleton() ...