stringwithformat用法 和 initWithFormat 有何不同

今天在看书上的一段代码时,发现NSString实例化时,有时用的是initWithFormat方法,有时用的是stringWithFormat,到底应该如何选择呢?
1、initWithFormat是实例方法
只能通过 NSString* str = [[NSString alloc] initWithFormat:@" World"] 调用,但是必须手动release来释放内存资源
2、stringWithFormat是类方法
可以直接用 NSString* str = [NSString stringWithFormat:@" World"] 调用,内存管理上是autorelease的,不用手动显式release
另外国外有个贴子对此有专门讨论()
而且提出了一个常见错误:
label.text = [[NSString alloc] initWithFormat:@""];
最后在dealloc中将label给release掉
但是仍然会发生内存泄漏!
原因在于:用label.text = ...时,实际是隐式调用的label的setText方法,这会retain label内部的字符串变量text(哪怕这个字符串的内容跟传进来的字符串内容相同,但系统仍然当成二个不同的字符串对象),所以最后release label时,实际上只释放了label内部的text字符串,但是最初用initWithFormat生成的字符串并未释放,最终造成了泄漏。
解决办法有二个:
NSString * str = [[NSString alloc] initWithFormat:@""];
label.text =
[str release]
最后在dealloc中再[label release]
label.text = [NSString stringWithFormat:@""];
然后剩下的事情交给NSAutoreleasePool
最后,如果你不确定你的代码是否有内存泄漏问题,可以用Xcode中的Build--&Build And Analyze 做初步的检查.
阅读(...) 评论()NSString中 initwithformat与stringwithformat差异
发布时间: 9:45:31
编辑:www.fx114.net 我要评论
本篇文章主要介绍了"NSString中 initwithformat与stringwithformat差异",主要涉及到NSString中 initwithformat与stringwithformat差异方面的内容,对于NSString中 initwithformat与stringwithformat差异感兴趣的同学可以参考一下。
NSString中 initwithformat与stringwithformat差异NSString中 initwithformat与stringwithformat区别
差别:1、initWithFormat是实例办法只能经由过程 NSString* str = [[NSString alloc] initWithFormat:@"%@",@"Hello World"] 调用,然则必须手动release来开释内存资料2、stringWithFormat是类办法自动释放内存可以直接用 NSString* str = [NSString stringWithFormat:@"%@",@"Hello World"] 调用,内存经管上是autorelease的,不用手动显式release别的国外有个贴子对此有专门评论辩论(/forum/iphone-sdk-development/29249-nsstring-initwithformat-vs-stringwithformat.html)并且提出了一个常见错误:label.text = [[NSString alloc] initWithFormat:@"%@",@"abc"];最后在dealloc中将label给release掉然则仍然会产生内存泄漏!原因在于:用label.text = ...时,实际是隐式调用的label的setText办法,这会retain label内部的字符串变量text(哪怕这个字符串的内容跟传进来的字符串内容雷同,但体系仍然当成二个不合的字符串对象),所以最后release label时,实际上只开释了label内部的text字符串,然则最初用initWithFormat生成的字符串并未开释,终极造成了泄漏。解决办法有二个:1、NSString * str = [[NSString alloc] initWithFormat:@"%@",@"abc"];label.text =[str release]最后在dealloc中再[label release]2、label.text = [NSString stringWithFormat:@"%@",@"abc"];然后剩下的工作交给NSAutoreleasePool最后,若是你不断定你的代码是否有内存泄漏题目,可以用Xcode中的Build--&Build And Analyze 做初步的搜检
一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!
二、互相尊重,对自己的言论和行为负责。
本文标题:
本页链接:温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
我存在,你精彩!
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
阅读(1433)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
在LOFTER的更多文章
loftPermalink:'',
id:'fks_',
blogTitle:'OC 可选多参数的实现',
blogAbstract:'
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}3029人阅读
前段时间被分配查应用的内存泄露问题,然后搜集了一大波内存管理相关的资料,并且在整个过程中狠狠的实践了一波。下面就把这段时间内碰到的坑(从别的地方也搜刮到很多坑),以及搜集到的一些理论知识(简洁版)总结一发。
背景:一个复杂的iOS应用可能会混合着MRR和ARC两种内存管理方式,就是有一部分文件MRR实现,而另一部分则是ARC实现(原因目测是因为复用MRR实现的旧代码)。所以就存在一种现象,如果后来的开发者没注意该文件是否为ARC模式时,则有可能会忘记对对象进行release等操作从而导致内存泄露的发生。
除了项目可能是ARC和MRR混合模式,有时候还有很多底层库是使用C/C++实现的,所以对于C/C++的内存管理也是需要有所了解的。
一、应用内存管理
从苹果的开发者文档里可以看到,一个 app 的内存分三类:
Leaked memory: Memory unreferenced by your application that cannot be used again or freed (also detectable by using the Leaks instrument).
Abandoned memory: Memory still referenced by your application that has no useful purpose.
Cached memory: Memory still referenced by your application that might be used again for better performance.
其中 Leaked memory和 Abandoned memory 都属于应该释放而没释放的内存,某种意义上来说都可以算内存泄露。而 Leaks工具只负责检测Leaked memory,而无法检测 Abandoned memory(这个是不是就是传说中的循环引用问题)相关的问题。
在 MRR 模式下 Leaked memory是比较常见,因为很容易忘了发送 release消息。而在 ARC 时代更常见的内存泄露是循环引用导致的 Abandoned memory,Leaks工具是无法直接检测出这类内存泄露问题的,可以借助一些别的工具(例如静态分析Static Analyze)。(引用出处【】)
1.1 内存管理原理
iOS平台内存管理采用的是引用计数机制,主要提供了MRR(Manual Retain-Release)和ARC(Automatic Reference Counting)两种内存管理方式,同时还提供了自动释放池这种半自动释放机制。
PS:这里的MRR就是传说中的MRR。只是我查iOS Developer文档时发现好像没有MRR这个叫法,也不知道这个叫法是怎么来的…
无论是MRR还是ARC,其本质都是引用计数。在MRR模式中,通过发送alloc,new, copy等方法可以创建一个对象,刚创建的对象引用计数值都为1。然后通过发送retain方法可以拥有该对象,同时会使得该对象的引用计数+1。最后可以向对象发送release消息放弃该对象所有权,同时会使得该对象的引用计数-1。当一个对象的引用计数为0时,则会被系统回收释放。
ARC实际上是一种编译器特性。编译器会在编译时自动在适当的位置插入retain, release消息来进行对象内存管理。而对于实际开发,只需要谨记:当一个对象被任何强指针引用时,则会被系统回收释放(可以理解为有几个强引用指向对象,则该对象引用计数为x,当没有强指针引用对象,则其引用计数为0)。
1.2 MRR内存管理准则
谁创建,谁释放。
谁retain,谁release/autorelease。
不要向不拥有的对象发送release。
二、检测工具介绍
2.1 Instrument — Leaks,Allocations,Analyze
我用到的检测内存泄露的工具主要是Xcode中集成的Leaks组件,这个组件的检测准确率比较高,可以查看到很多比如说是泄露大小,泄露产生的地方及其堆栈信息等。
这里的“泄露产生的地方”并不一定可以定位到具体发生泄漏的某一句代码,而是会标出发生泄漏的对象初始化分配内存的地方,然后需要具体去分析和跟踪该对象的内存管理来查找泄漏的原因。
Allocations工具是一个跟踪由应用程序分配的对象内存的工具。可以用来在疑似内存泄露的地方,通过反复操作,查看某些对象内存是否有被正常的释放,从而得知是否发生内存泄露。
Analyze是一款静态分析代码的工具。它可以发现一些逻辑错误,内存泄漏和声明错误(未使用变量)等。这个组件还可以检测出一些内存泄漏问题,比如一些比较明显的循环引用,CF库对象未release等相对简单的问题,通常是在进行其他方式检测之前就使用的方式,把一些简单的问题先发现并处理了。
参考资料:
2.2 内存检测组件
此外还有一些“植入”项目中的内存检测组件,比如说Facebook iOS 内存检测三剑客(FBAllocationTracker/FBMemoryProfiler/FBRetainCycleDetector),MSLeakHunter,,等等。
2.2.1 内存泄露检测组件原理简介
这些组件的其中大部分的实现原理都是类似的。主要就是灵活运用了OC中的Rumtime机制,以及各种OC对象生命周期管理相关的特性。这些组件为了实现对OC对象的内存监控,其本质就是在这些对象被分配和释放的时机进行监测。
比如说需要监测一个UIViewController类型的对象,就可以联想到iOS中VC的生命周期和UINavigationController有很大关系,因为后者在iOS应用中常常被用来管理大量VC的跳转控制。所以就可以考虑通过监控UINavigationController的navigation stack来达到检测VC是否发生内存泄露的目的。(以下这些方法都会被hook)
再比如说常见的NSObject对象,其alloc和dealloc方法就是对象生命周期中很重要的两个方法,分别是分配内存资源和释放内存资源时会被调用的方法。那么就可以考虑通过method swizzing方法替换alloc和dealloc这两个方法的实现,从而获得对象内存分配和释放的相关信息。
检测UIViewController内存泄漏的原理
(1)如何判断VC是否还在内存驻留?
答:利用ARC中weak指针指向的对象在对象释放时会自动置为nil的特性来检测VC是否在内存驻留。
(2) 在什么时机检测VC是否发生内存泄露?
答:通过监控UINavigationController的navigation stack,可以判断一个VC的生命周期的开始和结束。就是当VC从navigation stack移除且VC的viewDidDisappear方法执行时,可以粗略的认为一个VC的生命周期即将结束。这时候就可以创建一个指向该VC的weak指针,并初始化一个定时器对VC进行延时扫描,最后通过(1)中的方法判断VC是否还驻留在内存从而得出VC是否发生内存泄露的结论。
3.1 对象内存管理
在MRR模式下,通过new, copy, alloc方式创建的对象,记得release。一般在delloc中进行释放操作。当然局部内产生的也要在局部内进行释放。
点评:呵呵,在实践中发现最多的问题就是这个。尤其是在ARC和MRR都有的项目中。= =。我猜测原因之一可能是后面的代码修改者没意识到当前修改的文件是MRR模式的,所以在新增一些属性或成员变量后,没有在dealloc方法或对象使用完毕后及时的释放资源。
2. 在MRR模式下,发送了retain消息,记得也要发送release消息。并且在一个对象发送retain消息之前,也要考虑是否要release原来的对象。
碰到的一个栗子:
@interface classA{
NSString *_
- (void)functionA{
//正确的方式是这里要有: [_str release];
_str = [[NSString stringWithFormat:@"%d", @(213)] retain];
//后续代码...
- (void)functionB{
//正确的方式是这里要有: [_str release];
_str = [[NSString stringWithFormat:@"%d", @(213)] retain];
//后续代码...
Tips:这里存在一个问题就是functionA中对一个对象发送了retain消息,如果这时候又调用了functionB方法,str变量被重新赋值。此时如果没有先对str发送release消息的话,则会导致functionA中引用的对象发生内存泄露。
对于一般情况下使用的局部变量都会记得发送retain后发送release,然而在栗子中那种情况下,成员变量可能在不同方法中被重新赋值的时候,就要注意了!
3. 不论是MRR还是ARC情况下,使用Core Foundation框架(C语言实现的框架,其可以和Cocoa Foundation库中的对象进行类型转换)创建的对象需要手动进行内存管理。即需要手动调用CFRetain和CFRelease来管理对象内存。
Tips:这种情况没啥好说的了,就是记得CFRetain、CFRelease和retain、release一样要成对出现~
再多说一点就是Core Foundation框架和Cocoa Foundation对象指针转换的内容。Cocoa Foundation指针与Core Foundation指针转换,需要考虑的是所指向对象所有权的归属。ARC提供了3个修饰符来管理。【参考资料:、】
__bridge,什么也不做,仅仅是转换。此种情况下:
(1). 从Cocoa转换到Core,需要人工CFRetain,否则,Cocoa指针释放后, 传出去的指针则无效。
(2). 从Core转换到Cocoa,需要人工CFRelease,否则,Cocoa指针释放后,对象引用计数仍为1,不会被销毁。
__bridge_retained,转换后自动调用CFRetain,即帮助自动解决上述(1)的情形。
__bridge_transfer,转换后自动调用CFRelease,即帮助自动解决上述(2)的情形。
4. 使用NSAutoreleasePool创建的自动释放池,一定要确保其发送drain或release消息。这样创建的自动释放池对象才会被释放,同时被加入自动释放池的对象才能收到release消息,避免内存泄露。
碰到的栗子:
- (void)functionA{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *str = [[NSString alloc] initWithFormat:@"%d", @(213)];
[str release];
//执行各种代码...
//执行各种代码...
//问题就在这里:return 之前没有释放自动释放池!!!
//正确的做法,加上: [pool release];
[pool release];
Tips:栗子中的案例虽然看起来是个很逗比的错误,不过在实战中已经发现两处了…所以如果是MRR方式下这样使用自动释放池时,记得也要对自动释放池发送drain或release操作。如果是使用ARC的话,则不推荐栗子中使用自动释放池的方式,而是下面这种方式了。
@autoreleasepool {
// Code benefitting from a local autorelease pool.
既然说到自动释放池,那就顺便简单了解一下其实现原理,使用场景和一些注意事项吧。上面也有提到NSAutoreleasePool有两个方法drain和release,关于这两者的区别可以参考这些资料:【】【】。此外,还发现了一篇讲解AutoReleasePool的比较好的文章,里面也有解释了AutoReleasePool释放时间,原理等等:【】。
5. 函数返回的对象,是否加入自动释放池(延迟释放)。从内存管理的规范上来讲,如果一个函数需要返回一个对象,这个对象应该加入自动释放池中(”谁创建,谁释放”)?虽然说从某种角度来说,不加进自动释放池,而是由函数调用者负责该对象的释放也是可行的。如果函数返回的对象没有加入自动释放池,而函数调用者在外部又没有释放该对象,则就有可能造成内存泄露的现象。
(1)OC中有一些对象有多种创建的方法,比如说NSString, NSArray, NSDictionary之类的(还有它们的可变类型)。这些类都提供了两种类型的创建方式,一种是成员函数initWithXXX,另一种则是类函数stringWithXXX, arrayWithXXX(或array), dictionaryWithXXX(或dictionary)这些。
这些方法都是有区别的,第一种方式产生的对象需要手动release来释放内存,第二种方式产生的对象已经被加到autoreleasepool中,不需要手动release来释放内存。所以在项目中也要注意这些对象使用不同创建方式时所采用的不同的对象管理方法,针对这两种对象生成方式,也有很多讨论,大家自己看看吧哈哈哈哈哈。
参考资料:
(2)其中就碰到过Runtime方法中的class_copyIvarList,class_copyMethodList这些方法返回的对象没有被手动释放导致的内存泄漏。因为这些是C实现的函数,是需要手动对函数返回值进行free的,不然则会导致内存泄露。= =。这里也顺便提醒平时需要注意对于C/C++的实现,当见到malloc/new分配的对象,就应该检查该对象有没有对应的free/delete操作,这些地方往往也是内存泄漏产生的地方。
3.2 引用循环
这是无论在MRR还是ARC下都存在的一种导致内存泄露的情况,尤其是在ARC中,如果发生内存泄漏,其一般都会是罪魁祸首。尤其是在使用block的时候,更要注意适当处理以避免强引用循环的发生。
后续有待更新。。。。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:21224次
积分:1093
积分:1093
排名:千里之外
原创:84篇
(2)(1)(21)(23)(31)(9)}

我要回帖

更多关于 initwithformat 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信