如何管理ios内部ios11查看储存空间慢

iOS怎么查看内存里所有文件,就是类似于安卓的文件管理器。【iphone6吧】_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:1,463,707贴子:
iOS怎么查看内存里所有文件,就是类似于安卓的文件管理器。收藏
设置 - 通用 - 用量 - 存储用量
特斯拉,有钱
潜水出来冒泡
越狱,然后PP助手里面就会有个“文件(越狱)”。这就是你需要的了
登录百度帐号推荐应用Objective-C 内存管理之dealloc方法中变量释放处理
(一).关于nil
Calling Methods on Nil
In Objective-C, the nil object is the functional equivalent to the NULLpointer in many other languages.
The difference is that you can call methods on nil without crashing or throwing an exception.
在Objective-C中,nil对象与许多其他语言中的NULL指针有同样的功能。
区别在于,你可以向一个nil对象发送任何信息,即让一个nil的对象调用任何方法,而不会导致程序的崩溃或者抛出异常。
这是一个有用的基础知识
另外在cocoachina (http://www. )论坛有人指出
对象被release后 系统会将该块内存标记为可用(可重新分配)
nil就是起到个重置指针的作用 对内存的释放无意义
防止出现调用错误。
(二).结论:
不同的环境下使用不同的代码处理是中庸之道,也就是
如果你在开发和调试,测试阶段
使用可以直接暴露问题代码的dealloc处理方式:
在dealloc中即仅仅release你的变量。
如果你把程序发布给用户使用,使用先release,后赋值nil的方式
这样,不会暴露crash给用户
(三)..以下是参考:
首先,这是一篇非常好的博客,详细说明了关于dealloc中的几种处理方式的论证
英文好的看原文,不要被我的翻译误解。
stackoverflow上几个有价值的参考,上面讨论了开发者的在这方面的经验:
(四)..现在,正式对这篇博客翻译:
声明:如果有错误翻译或者错字等请指出,但是本人仅是翻译供学习探讨所用,任何问题与纠纷居于本人无关,谢谢合作!
Last week there was a bit of a Twitter in-fight in the iOS community over the "right" way to release your instance variables in dealloc. I think Rob actually started it, to be honest, but I
probably shouldn't be bringing that up.
上一周,在Twitter iOS 社区上有一场关于任何正确在dealloc方法中正确释放你的变量的激烈讨论(辩论大战!),我认为是由Rob引发的,但说实话,我其实不应该透露这一点(好笑,作者不想八卦,却仍然给了Rob的连接~).
Basically, several developers were claiming that there's never a reason to set an instance variable to nil in dealloc, while others were arguing that you should always
基本上,几个开发者都声明到,没有任何理由允许在dealloc方法中把一个实例变量设值为nil,同时其他极为争辩到你应该这么做,即在dealloc中,对实例变量赋值为nil.
To me, there didn't seem to be a clear and compelling winner between the two approaches. I've used both in my career. However, since we're in the process of trying to decide which approach to use in the next edition
of Beginning iPhone Development, I reached out to Apple's Developer Tools Evangelist, , to see if there was an official or recommended approach to handling instance variables in dealloc.
对我来说,似乎在这两种方式中,没有出现一个清晰地完全的胜利者。在我的开发过程中,这两种方式我都用过。但是,既然我们在尝试将这两个方法取其一而用到下一版本的 Beginning iPhone Development中,我向苹果的开发者 Michael Jurewitz 求助,来探索在dealloc中如何处理实例变量这件事情上,是否存在一个官方的或者推荐的方法。
Other than the fact that you should never, ever use mutators in dealloc (or init, for that matter), Apple does not have an official recommendation
on the subject.
除了在dealloc或者init方法中,你最好不要使用设值方法(eg:[self.xxxx message];),苹果没有提供过关于dealloc中释放实例变量的官方推荐方法。
However, Michael and
and a former Evangelist
himself, had discussed this issue extensively last week. They kindly shared their conclusions with me and said it was okay for me to turn it into a blog post. So, here it is. Hopefully, I've captured everything correctly.
然而,Michael and
和一个前 Evangelist 他自己(Evangelist本意是传播福音的人,我猜是那些宣讲苹果官方技术的人员,就是普及苹果开发技术的一些专家吧)关于此问题在上周进行了一场较广泛的讨论。他们非常有好的与我分享了他们的结论结果并且同意我在博客上登载出来,所以,结果是这样的,希望我已经正确地搜集到每个方面了。
The Two Major Approachs
Just to make sure we're all on the same page, let's look at the two approaches that made up the two different sides of the argument last week.
两种主要的方法
首先来确认我们达成共识,让我们先看看上周两个不同支持者的两种方法。
Just Release
仅仅release
The more traditional approach is to simply release your instance variables and leave them pointing to the released (and potentially deallocated) object, like so:
最传统的方法是仅仅release掉你的实例变量并且任其只想一个已经release的对象上,就像这样:
- (void)dealloc
[Sneezy release];
[Sleepy release];
[Dopey release];
[Doc release];
[Happy release];
[Bashful release];
[Grumpy release];
[super dealloc];
In this approach, each of the pointers will be pointing to a potentialy invalid object for a very short period of time — until the method returns — at which point the instance variable will disappear along with its
owning object. In a single-threaded application (the pointer would have to be accessed by something triggered by code in either this object's implementation of dealloc or in the dealloc of one of its superclasses,
there's very little chance that the instance variables will be used before they go away , which is probably what has led to the proclamations made by several that there's "no value in setting instance variables to nil" in dealloc.
在这个方法上,每一个指针都会在非常短的时间上的指向一块可能非法的对象上,知道方法执行完毕,在那时,实例变量会随着它的拥有者一同消失。在一个单线程的应用中(指针会不得不被或者是对象的自己实现dealloc又或者在它父类的dealloc中一些启动的东西访问到,一个实例变量在它小事之前会被使用到是一个小概率事件。但如果发生了,就正中下怀了,也就是那些宣告说需要在dealloc方法中赋值给实例变量nil值观点的人所顾虑的那样。
In a multi-threaded environment, however, there is a very real possibility that the pointer will be accessed between the time that it is deallocated and the time that its object is done being deallocated. Generally
speaking, this is only going to happen if you've got a bug elsewhere in your code, but let's face it, you may very well. Anyone who codes on the assumption that all of their code is perfect is begging for a smackdown, and Xcode's just biding its time waiting
for the opportunity.
然而,在一个多线程的环境里,一个指针在本身被dealloc以后与它的拥有者对象被dealloc之前被访问到,却是一个很有可能发生的事情的。一般而言,如果你在别处代码中遇到bug,这里成为了问题的源头,但是让我们面对它,你会变得更好。任何建立在自己的代码是完美的这个假设上写代码的人都是在掩耳盗铃,Xcode仅仅是在伺机而动,等待机会报错给你。
Release and nil
In the last few years, another approach to dealloc has become more common. In this approach, you release your instance variable and then immediately set them to nil before
releasing the next instance variable. It's common to actually put the release and the assignment to nil on the same line separated by a comma rather than on consecutive lines
separated by semicolons, though that's purely stylistic and has no affect on the way the code is compiled. Here's what our previous dealloc method might look like using this approach:
在过去的几年,另一个在dealloc中处理的方法变得越来越普及,在这个方法中,你release你的实例变量并且在releasing下一个实例变量前立即把它赋值为nil.比较普遍的做法是,将release语句与赋值nil语句用一个都好隔开放到同一行而不是用分号隔开为多行,尽管这样做仅仅是表层代码的长相上,在编译时是无任何差别的。下面是我们之前的dealloc用这种方法后的样子:
- (void)dealloc
[sneezy release], sneezy =
[sleepy release], sleepy =
[dopey release], dopey =
[doc release], doc =
[happy release], happy =
[bashful release], bashful =
[grumpy release], grumpy =
[super dealloc];
In this case, if some piece of code accesses a pointer between the time that dealloc begins and the object is actually deallocated, it will almost certainly fail gracefully because sending
messages to nil is perfectly okay in Objective-C. However, you're doing a tiny bit of extra work by assigning nil to a bunch of pointers that are going to go away momentarily,
and you're creating a little bit of extra typing for yourself in every class.
在这种情况下如果有代码访问一个开始被dealloc但是还没被完全dealloc间的指针时,这样的操作是无效失败的,因为在Objective-C中,想一个nil值的对象发送消息是没有问题,不会引发错误的。但是,如果你赋值给一些会立即消失的对象nil值,你却做了一些额外的工作,在每一个你的类中都会制造这些额外的输入开支。
The Showdown 最后一战
So, here's the real truth of the matter: The vast majority of the time, it's not going to make any noticeable difference whatsoever. If you're not accessing instance variables that have been released, there's simply not going to
be any difference in the behavior between the two approaches. If you are, however, then the question is: what do you want to happen when your code does that bad thing?
那么,接下来是最重要的地方。绝大多数的时候,没有什么明显的区别。如果你不去访问那些被释放掉的实例变量,在这两种方法间没有任何的功能方面结果的区别。但如果你访问了,那么问题是,你想你的代码如何针对这种情况做出反应?
In the first approach, your application will usually crash with an EXC_BAD_ACCESS, though you could also end up with any manner of odd behavior (which we call a "heisenbug") if the released object is deallocated and
its memory is then reused for another object owned by your application. In those cases, you may get a selector not recognized exception when the message is sent to the deallocated object, or you may simply get unexpected
behavior from the same method being called on the wrong object.
第一种方法下,你的程序通常下会崩溃,警告给你EXC_BAD_ACCESS,虽然你还可能最后得到一些诡异的结果(通常我们都称它为heisenbug,这种bug是诡异的出现,并且通常不好重现,以致难以修补)像是一个released对象被dealloced并且它的内存之后被你的冲虚中另一个对象利用到。在这种情况下,你可能得到一个selector not recognized异常,当消息被发送给一个被delloced完的对象,或者在一个错误的对象执行你调用的方法后,你可能仅仅得到一个异常结果。
In the other approach, your application will quietly send a message to nil and go about its merry way, generally without a crash or any other immediately identifiable problem.
在另一个方法下,你的程序会给一个nil值的对象发送消息并且就这么不了了之了~什么都没有发生,没有程序崩溃(no crash!!),没有其他任何实时可分辨的问题出现。
The former approach is actually good when you're developing, debugging, and doing unit testing, because it makes it easier to find your problematic code. On the other hand, that approach is really, really bad in a shipping application because you really don't
want to crash on your users if you can avoid it.
前一种方法在你正在开发,调试或者做单元测试时会更有优势。因为它会让你很容易找到问题代码。另一方面,这个方法会非常非常的糟糕,在你发布你的程序后,因为你不想你的用户在使用时遇到程序crash并且这是你可以避免的crash!。
The latter approach, conversely, can hide bugs during development, but handles those bugs more gracefully when they happen, and you're far less likely to have your application go up in a big ball of fire in front of your users.
后一种方法,相反地会在开发过程中掩盖住你的bugs,但是在bugs发生的时候更温和的处理掉了,但同时你会让或多或少可能让你的程序被火球包裹,然后呈现给你的用户。
The Winner? 胜利者?
There really isn't a clear cut winner, which is probably why Apple doesn't have an official recommendation or stance. During their discussion, Matt and Michael came up with a "best of both worlds" solution, but it requires a fair
bit of extra code over either of the common approaches.
其实并没有一个明显的胜利者,或许这就是为什么苹果没有给出一个官方的推荐或者例子的原因。在他们讨论期间,Matt and Michael 得出一个权衡之计,既两种情况都会使程序更好更稳固的解决方案,但是这需要一些额外的代码,在这两种通常的方法基础上。
If you want your application to crash when a released pointer is accessed during development and debugging, the solution is to use the traditional approach in your debug configuration. If you want your application to degrade gracefully for your users, the solution
is to use the newer approach in your release and ad hoc configurations.
在你开发和调试期间,当一个指针被访问时如果你想要你的程序直接crash,解决方案就是用最传统的方法在你的调试环境。如果你想你的程序友好的呈现给用户,解决方法是用新的方法,在你的release并且加上额外配置。
One somewhat pedantic implementation of this approach would be this:
一种比较死板的实现这个理论的方法会像是这样:
- (void)dealloc
[Sneezy release];
[Sleepy release];
[Dopey release];
[Doc release];
[Happy release];
[Bashful release];
[Grumpy release];
[super dealloc];
[sneezy release], sneezy = nil;
[sleepy release], sleepy = nil;
[dopey release], dopey = nil;
[doc release], doc = nil;
[happy release], happy = nil;
[bashful release], bashful = nil;
[grumpy release], grumpy = nil;
[super dealloc];
That code assumes that your debug configuration has a precompiler definition of DEBUG, which you usually have to add to your Xcode project - most Xcode project templates do not provide it for you. There are several
ways you can add it, but I typically just use the Preprocessor Macros setting in the project's Build
这个代码假设你的调试配置中有一个预编译宏定义,你必须将它添加到你的Xcode 工程中,大多数Xcode工程模板不会提供给你这个。有多种方式添加,但是代表性的,我只使用在工程Build下的预编译宏设值
Although the code above does, indeed, give us the best of both worlds - a crash during development and debugging and graceful degrading for customers - it at least doubles the amount of code we have to write in every
class. We can do better than that, though. How about a little macro magic? If we add the following macro to our project's .pch file:
尽管上面的代码给了我们权衡的答案,也就是在开发和调试时程序会crash,但是在发布给用户时会平稳的处理掉。可是它至少在我们每一个类中都多使用照原来两倍的代码。我们可以做的更好,用一些宏怎么样?如果我们在.pch文件中加入下面的宏变量:
#define MCRelease(x) [x release]
#define MCRelease(x) [x release], x = nil
We can then use that macro in dealloc, and our best-of-both-worlds code becomes much shorter and more readable:
我们可以在dealloc中使用它们,并且我们的“权衡方法”变得更短,更加易读:
- (void)dealloc
MCRelease(sneezy);
MCRelease(sleepy);
MCRelease(dopey);
MCRelease(doc);
MCRelease(happy);
MCRelease(bashful);
MCRelease(grumpy);
[super dealloc];
Once you've got the macro in your project, this option is actually no more work or typing than either of the other dealloc methods.
一旦你在你的工程中写了宏,这种选择不会比之前的两种dealloc方法花费额外的工作。
But, you know what? If you want to keep doing it the way you've always done it, it's really fine, regardless of which way you do it. If you're consistent in your use and are aware of the tradeoffs, there's really no compelling reason to use one over the other
outside of personal preference.
但是你知道么?如果你想保持你之前在dealloc处理对象的方式,其实也是不错的。无论你现则哪种方式,如果你对你使用并且意识到其中利弊,真的什么强制的理由让一个人改变他的个人选择。
So, in other words, it's kind of a silly thing for us all to argue over, especially when there's already politics, religions, and sports to fill that role.
那么,也就是说,我们没有必要争论下去了,需要争论的东西太多了,像是政策,种族,体育那些...
The Garbage Collection Angle
There's one last point I want to address. I've heard a few times from different people that setting an instance variable to nil indealloc acts
as a hint to the garbage collector when you're using the allowed-not-required GC option (when the required option is being used, dealloc isn't even called, finalize is).
If this were true, forward compatibility would be another possible argument for preferring the newer approach to dealloc over the traditional approach.
还有最后一点我想要指出。好几次,我从不同的人听到过,在dealloc方法中赋值给实例变量nil值会起到给垃圾回收器一个钩子的作用,当你用allowed-not-required GC 选项(当required-option被使用,dealloc不会被调用,finalize会)。如果这是真的,向前兼容会变成新的争论,针对在dealloc里新的方法与传统的方法之间。
While it is true that in Java and some other languages with garbage collection, nulling out a pointer that you're done with helps the garbage collector know that you're done with that object, so it's not altogether
unlikely that Objective-C's garbage collector does the same thing, however any benefit to nil'ing out instance variables once we get garbage collection in iOS would be marginal at best. I haven't been able to find
anything authoritative that supports this claim, but even if it's 100% true, it seems likely that when the owning object is deallocated a few instructions later, the garbage collector will realize that the deallocated object is done with anything it was using.
在java和一些其他的自带垃圾回收的机制的语言中,给一个指针赋值null会帮助你让垃圾回收器知道你已经用完这个对象了,它们不等同于Objective-C的垃圾回收器做同样的操作,但是使用nil赋值给实例变量的益处,一旦是iOS的垃圾回收机制它都变得相当的边缘化了。我没能找到任何权威性的论据来支持这个声明,但是即使它是百分百真的,似乎当一个被拥有的对象被指令dealloc执行后,垃圾回收器会意识到那个被dealloc的对象已经做完所有该做的事情。
If there is a benefit in this scenario, which seems unlikely, it seems like it would be such a tiny difference that it wouldn't even make sense to factor it into your decision. That being said, I have no firm evidence one way or the other on this issue and
would welcome being enlightened.
在这种情境下有没有好处,貌似没有...似乎它都不能成为你做决定使用那种方法的一个参考因素。也就是说,我没有有力的证据,在这个问题上欢迎大家来讨论互相启发。
看过本文的人也看了:
我要留言技术领域:
取消收藏确定要取消收藏吗?
删除图谱提示你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?
删除节点提示无法删除该知识节点,因该节点下仍保存有相关知识内容!
删除节点提示你确定要删除该知识节点吗?Posts - 79,
Articles - 0,
Comments - 1683
CODING 完美世界...
17:10 by KenshinCui, ... 阅读,
概述 我们知道在程序运行过程中要创建大量的对象,和其他高级语言类似,在ObjC中对象时存储在堆中的,系统并不会自动释放堆中的内存(注意基本类型是由系统自己管理的,放在栈上)。如果一个对象创建并使用后没有得到及时释放那么就会占用大量内存。其他高级语言如C#、Java都是通过垃圾回收来(GC)解决这个问题的,但在OjbC中并没有类似的垃圾回收机制,因此它的内存管理就需要由开发人员手动维护。今天将着重介绍ObjC内存管理:
引用计数器 在Xcode4.2及之后的版本中由于引入了ARC(Automatic Reference Counting)机制,程序编译时Xcode可以自动给你的代码添加内存释放代码,如果编写手动释放代码Xcode会报错,因此在今天的内容中如果你使用的是Xcode4.2之后的版本(相信现在大部分朋友用的版本都比这个要高),必须手动关闭ARC,这样才有助于你理解ObjC的内存回收机制。
ObjC中的内存管理机制跟C语言中指针的内容是同样重要的,要开发一个程序并不难,但是优秀的程序则更测重于内存管理,它们往往占用内存更少,运行更加流畅。虽然在新版Xcode引入了ARC,但是很多时候它并不能完全解决你的问题。在Xcode中关闭ARC:项目属性—Build Settings--搜索“garbage”找到Objective-C Automatic Reference Counting设置为No即可。 内存管理原理 我们都知道在C#、Java中都有GC在自动管理内存,当我们实例化一个对象之后通常会有一个变量来引用这个对象(变量中存储对象地址),当这个引用变量不再使用之后(也就是不再引用这个对象)此时GC就会自动回收这个对象,简单的说就是:当一个对象没有任何变量引用的时候就会被回收。 例如下面的C#代码片段using S
namespace GC
class Program
private static void Test()
object o=new object();
static void Main(string[] args)
上面是一段C#代码,在Test()方法中,通过new Object()创建了一个对象,o是一个对象的引用(存储了对象的地址),它是一个局部变量,作用范围就是Test()方法内部。
当执行完Test()方法之后o就会被释放,此时由于没有变量在引用new Object()这个对象,因此GC会自动回收这个对象所占用的空间。
但是在ObjC中没有垃圾回收机制,那么ObjC中内存又是如何管理的呢?其实在ObjC中内存的管理是依赖对象引用计数器来进行的:在ObjC中每个对象内部都有一个与之对应的整数(retainCount),叫“引用计数器”,当一个对象在创建之后它的引用计数器为1,当调用这个对象的alloc、retain、new、copy方法之后引用计数器自动在原来的基础上加1(ObjC中调用一个对象的方法就是给这个对象发送一个消息),当调用这个对象的release方法之后它的引用计数器减1,如果一个对象的引用计数器为0,则系统会自动调用这个对象的dealloc方法来销毁这个对象。
下面通过一个简单的例子看一下引用计数器的知识:
Person.h//
MemoryManage
Kenshin Cui on 14-2-15.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import &Foundation/Foundation.h&
@interface Person : NSObject
#pragma mark - 属性
@property (nonatomic,copy) NSString *
@property (nonatomic,assign) int
Person.m//
MemoryManage
Kenshin Cui on 14-2-15.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import "Person.h"
@implementation Person
#pragma mark - 覆盖方法
#pragma mark 重写dealloc方法,在这个方法中通常进行对象释放操作
-(void)dealloc{
NSLog(@"Invoke Person's dealloc method.");
[super dealloc];//注意最后一定要调用父类的dealloc方法(两个目的:一是父类可能有其他引用对象需要释放;二是:当前对象真正的释放操作是在super的dealloc中完成的)
MemoryManage
Created by Kenshin Cui on 14-2-15.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import &Foundation/Foundation.h&
#import "Person.h"
void Test1(){
Person *p=[[Person alloc]init]; //调用alloc,引用计数器+1
p.name=@"Kenshin";
NSLog(@"retainCount=%lu",[p retainCount]);
//结果:retainCount=1
[p release];
//结果:Invoke Person's dealloc method.
//上面调用过release方法,p指向的对象就会被销毁,但是此时变量p中还存放着Person对象的地址,
//如果不设置p=nil,则p就是一个野指针,它指向的内存已经不属于这个程序,因此是很危险的
//如果不设置p=nil,此时如果再调用对象release会报错,但是如果此时p已经是空指针了,
//则在ObjC中给空指针发送消息是不会报错的
[p release];
void Test2(){
Person *p=[[Person alloc]init];
p.name=@"Kenshin";
NSLog(@"retainCount=%lu",[p retainCount]);
//结果:retainCount=1
[p retain];//引用计数器+1
NSLog(@"retainCount=%lu",[p retainCount]);
//结果:retainCount=2
[p release];//调用1次release引用计数器-1
NSLog(@"retainCount=%lu",[p retainCount]);
//结果:retainCount=1
[p release];
//结果:Invoke Person's dealloc method.
int main(int argc, const char * argv[]) {
@autoreleasepool {
在上面的代码中我们可以通过dealloc方法来查看是否一个对象已经被回收,如果没有被回收则有可能造成内存泄露。如果一个对象被释放之后,那么最后引用它的变量我们手动设置为nil,否则可能造成野指针错误,而且需要注意在ObjC中给空对象发送消息是不会引起错误的。
野指针错误形式在Xcode中通常表现为:Thread 1:EXC_BAD_ACCESS(code=EXC_I386_GPFLT)错误。因为你访问了一块已经不属于你的内存。
内存释放的原则
手动管理内存有时候并不容易,因为对象的引用有时候是错综复杂的,对象之间可能互相交叉引用,此时需要遵循一个法则:谁创建,谁释放。
假设现在有一个人员Person类,每个Person可能会购买一辆汽车Car,通常情况下购买汽车这个活动我们可能会单独抽取到一个方法中,同时买车的过程中我们可能会多看几辆来最终确定理想的车,现在我们的代码如下:
MemoryManage
Created by Kenshin Cui on 14-2-15.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import &Foundation/Foundation.h&
@interface Car : NSObject
#pragma mark - 属性
#pragma mark 车牌号
@property (nonatomic,copy) NSString *
#pragma mark - 公共方法
#pragma mark 运行方法
MemoryManage
Created by Kenshin Cui on 14-2-15.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import "Car.h"
@implementation Car
#pragma mark - 公共方法
#pragma mark 运行方法
-(void)run{
NSLog(@"Car(%@) run.",self.no);
#pragma mark - 覆盖方法
#pragma mark 重写dealloc方法
-(void)dealloc{
NSLog(@"Invoke Car(%@) dealloc method.",self.no);
[super dealloc];
Person.h//
MemoryManage
Created by Kenshin Cui on 14-2-15.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import &Foundation/Foundation.h&
@interface Person : NSObject{
#pragma mark - 属性
#pragma mark 姓名
@property (nonatomic,copy) NSString *
#pragma mark - 公共方法
#pragma mark Car属性的set方法
-(void)setCar:(Car *)
#pragma mark
Car属性的get方法
Person.m//
MemoryManage
Created by Kenshin Cui on 14-2-15.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import "Person.h"
#import "Car.h"
@implementation Person
#pragma mark - 公共方法
#pragma mark Car属性的set方法
-(void)setCar:(Car *)car{
if (_car!=car) { //首先判断要赋值的变量和当前成员变量是不是同一个变量
[_car release]; //释放之前的对象
_car=[car retain];//赋值时重新retain
#pragma mark
Car属性的get方法
-(Car *)car{
#pragma mark - 覆盖方法
#pragma mark 重写dealloc方法
-(void)dealloc{
NSLog(@"Invoke Person(%@) dealloc method.",self.name);
[_car release];//在此释放对象,即使没有赋值过由于空指针也不会出错
[super dealloc];
MemoryManage
Created by Kenshin Cui on 14-2-15.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import &Foundation/Foundation.h&
#import "Person.h"
#import "Car.h"
void getCar(Person *p){
Car *car1=[[Car alloc]init];
car1.no=@"888888";
p.car=car1;
NSLog(@"retainCount(p)=%lu",[p retainCount]);
Car *car2=[[Car alloc]init];
car2.no=@"666666";
[car1 release];
[car2 release];
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p=[[Person alloc]init];
p.name=@"Kenshin";
getCar(p);
[p.car run];
[p release];
程序运行结果:
从运行结果来看创建的三个对象p、car1、car2都被回收了,而且[p.car run]也能顺利运行,已经达到了我们的需求。但是这里需要重点解释一下setCar方法的实现,setCar方法中为什么没有写成如下形式:-(void)setCar:(Car *)car{
前面在我们说到属性的定义时不是都采用的这种方式吗?
根据前面说到的内存释放原则,getCar方法完全符合,在这个方法中定义的两个对象car1、car2也都是在这个方法中释放的,包括main函数中的p对象也是在main函数中定义和释放的。但是如果发现调用完getCar方法之后紧接着调用了汽车的run方法,当然这在程序设计和开发过程中应该是再普通不过的设计了。如果setCar写成“_car=car”的形式,当调用完getCar方法后,人员的car属性被释放了,此时调用run方法是会报错的(大家自己可以试试)。但是如下的方式却不会有问题:-(void)setCar:(Car *)car{
if (_car!=car) { //首先判断要赋值的变量和当前成员变量是不是同一个变量
[_car release]; //释放之前的对象
_car=[car retain];//赋值时重新retain
因为在这个方法中我们通过[car retain]保证每次属性赋值的时候对象引用计数器+1,这样一来调用过getCar方法可以保证人员的car属性不会被释放,其次为了保证上一次的赋值对象(car1)能够正常释放,我们在赋新值之前对原有的值进行release操作。最后在Person的dealloc方法中对_car进行一次release操作(因为setCar中做了一次retain操作)保证_car能正常回收。
像上面这样编写setCar方法的情况是比较多的,那么如何使用@property进行自动实现呢?答案就是使用属性参数,例如上面car属性的setter方法,可以通过@property定义如下:@property (nonatomic,retain) Car *
你会发现此刻我们不必手动实现car的getter、setter方法程序仍然没有内存泄露。其实大家也应该都已经看到前面Person的name属性定义的时候我们同样加上了(nonatomic,copy)参数,这些参数到底是什么意思呢?
@property的参数分为三类,也就是说参数最多可以有三个,中间用逗号分隔,每类参数可以从上表三类参数中人选一个。如果不进行设置或者只设置其中一类参数,程序会使用三类中的各个默认参数,默认参数:(atomic,readwrite,assign)
一般情况下如果在多线程开发中一个属性可能会被两个及两个以上的线程同时访问,此时可以考虑atomic属性,否则建议使用nonatomic,不加锁,效率较高;readwirte方法会生成getter、setter两个方法,如果使用readonly则只生成getter方法;关于set方法处理需要特别说明,假设我们定义一个属性a,这里列出三种方式的生成代码:
assign,用于基本数据类型-(void)setA:(int)a{
retain,通常用于非字符串对象-(void)setA:(Car *)a{
if(_a!=a){
[_a release];
_a=[a retain];
copy,通常用于字符串对象、block、NSArray、NSDictionary-(void)setA:(NSString *)a{
if(_a!=a){
[_a release];
_a=[a copy];
备注:本文基于MRC进行介绍,ARC下的情况不同,请参阅其他文章,例如ARC下基本数据类型默认的属性参数为(atomic,readwrite,assign),对象类型默认的属性参数为(atomic,readwrite,strong)
自动释放池
在ObjC中也有一种内存自动释放的机制叫做“自动引用计数”(或“自动释放池”),与C#、Java不同的是,这只是一种半自动的机制,有些操作还是需要我们手动设置的。自动内存释放使用@autoreleasepool关键字声明一个代码块,如果一个对象在初始化时调用了autorelase方法,那么当代码块执行完之后,在块中调用过autorelease方法的对象都会自动调用一次release方法。这样一来就起到了自动释放的作用,同时对象的销毁过程也得到了延迟(统一调用release方法)。看下面的代码:
Person.h//
MemoryManage
Created by Kenshin Cui on 14-2-15.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import &Foundation/Foundation.h&
@interface Person : NSObject
#pragma mark - 属性
#pragma mark 姓名
@property (nonatomic,copy) NSString *
#pragma mark - 公共方法
#pragma mark 带参数的构造函数
-(Person *)initWithName:(NSString *)
#pragma mark 取得一个对象(静态方法)
+(Person *)personWithName:(NSString *)
Person.m//
MemoryManage
Created by Kenshin Cui on 14-2-15.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import "Person.h"
@implementation Person
#pragma mark - 公共方法
#pragma mark 带参数的构造函数
-(Person *)initWithName:(NSString *)name{
if(self=[super init]){
self.name=
#pragma mark 取得一个对象(静态方法)
+(Person *)personWithName:(NSString *)name{
Person *p=[[[Person alloc]initWithName:name] autorelease];//注意这里调用了autorelease
#pragma mark - 覆盖方法
#pragma mark 重写dealloc方法
-(void)dealloc{
NSLog(@"Invoke Person(%@) dealloc method.",self.name);
[super dealloc];
MemoryManage
Created by Kenshin Cui on 14-2-15.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import &Foundation/Foundation.h&
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *person1=[[Person alloc]init];
[person1 autorelease];//调用了autorelease方法后面就不需要手动调用release方法了
person1.name=@"Kenshin";//由于autorelease是延迟释放,所以这里仍然可以使用person1
Person *person2=[[[Person alloc]initWithName:@"Kaoru"] autorelease];//调用了autorelease方法
Person *person3=[Person personWithName:@"rosa"];//内部已经调用了autorelease,所以不需要手动释放,这也符合内存管理原则,因为这里并没有alloc所以不需要release或者autorelease
Person *person4=[Person personWithName:@"jack"];
[person4 retain];
Invoke Person(rosa) dealloc method.
Invoke Person(Kaoru) dealloc method.
Invoke Person(Kenshin) dealloc method.
当上面@autoreleaespool代码块执行完之后,三个对象都得到了释放,但是person4并没有释放,原因很简单,由于我们手动retain了一次,当自动释放池释放后调用四个对的release方法,当调用完person4的release之后它的引用计数器为1,所有它并没有释放(这是一个反例,会造成内存泄露);autorelase方法将一个对象的内存释放延迟到了自动释放池销毁的时候,因此上面person1,调用完autorelase之后它还存在,因此给name赋值不会有任何问题;在ObjC中通常如果一个静态方法返回一个对象本身的话,在静态方法中我们需要调用autorelease方法,因为按照内存释放原则,在外部使用时不会进行alloc操作也就不需要再调用release或者autorelase,所以这个操作需要放到静态方法内部完成。
对于自动内存释放简单总结一下:
autorelease方法不会改变对象的引用计数器,只是将这个对象放到自动释放池中;
自动释放池实质是当自动释放池销毁后调用对象的release方法,不一定就能销毁对象(例如如果一个对象的引用计数器&1则此时就无法销毁);
由于自动释放池最后统一销毁对象,因此如果一个操作比较占用内存(对象比较多或者对象占用资源比较多),最好不要放到自动释放池或者考虑放到多个自动释放池;
ObjC中类库中的静态方法一般都不需要手动释放,内部已经调用了autorelease方法;

我要回帖

更多关于 ios11查看储存空间慢 的文章

 

随机推荐