OC内存管理
分析一下C中容易出错的内存代码
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
char *s = "Gello World!";//s是放在只读数据段
s[0] = 'H';//只读数据段是不能被修改的,所以该操作是错的!
//修改为 char s[]="Gello World";是对的!
printf("%s\n",s);
}
return 0;
}
第二个错题:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void get_memory(char *p, int capacity) {
p = malloc(sizeof *p * capacity);
}
int main() {
char *str = NULL;//由于这里str本身就是指针所以要操作str必须传入的是
//二重指针,正确代码参见以下
get_memory(str, 100);
strcpy(str, "Hello, world!");
printf("%s\n", str);
return 0;
}
第二题的正确代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void get_memory(char **p,int capacity){
//指针的第二个作用就是申请堆空间
*p = malloc (sizeof **p * capacity);
}
//指针的第一个用途就是实现跨栈操作
void swap (int *a,int *b){
int temp = *a;
*a = *b;
*b = temp;
}
//任何时候希望通过函数调用修改传入的参数(对调用者产生影响)
//那就不能只传参数的值而是要传参数的地址
//如果传入的参数本身就是指针。那么就要使用指向指针的指针
//指针的第一个用途就是实现跨栈操作
int main(){
int a=9;int b=0;
swap(&a,&b);//传的是a和b的地址
printf("%d %d\n",a,b);
char *str = NULL;
get_memory(&str,100);
if(str){//如果空间申请成功
strcpy(str,"Hello,world");
printf("%s\n", str);
free(str);//堆空间不会随着栈的消失而消失需要手动释放;
str = NULL;//如果以后还要用str,不置空的话使用str可能失败表面产生野指针
}
return 0;
}
注意事项:前面为str申请了堆空间,一定要记得三个操作:
1.判断申请空间是否成功(加上if判断语句)if(str)
2.手动free释放掉空间;free(p);
3.将指针置空避免产生野指针!!str == null;
常见内存错误第三题;
#include <stdio.h>
char *get_memory()
{
char str[] = "hello, world";
return str;
}
int main() {
char *str = get_memory();
printf("%s\n", str);
return 0;
}
正确的代码修改:
#include <stdio.h>
char *get_memory()
{
char *str = "hello, world";
return str;
}
int main() {
char *str = get_memory();
printf("%s\n", str);
return 0;
}
注意: char str[] = "hello world"
c的数组是放在栈空间的,一个函数只能返回占空间的值而不能返回栈空间的地址
常见内存错误第四题:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *get_memory(int capacity) {
char *str = malloc(sizeof *str * capacity);
return str;
}
int main() {
char *str = get_memory(100);
strcpy(str, "Hello, world!");
printf("%s\n", str);
return 0;
}
修改后的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *get_memory(int capacity) {
char *str = malloc(sizeof *str * capacity);
return str;
}
int main() {
char *str = get_memory(100);
if(str){
strcpy(str, "Hello, world!");
printf("%s\n", str);
free(str);
str = NULL;
}
return 0;
}
注意:申请空间后一定要判断,然后释放掉空间,最后将指针置空!!
为了解决上述问题,在Objective-C中引入了引用计数的概念。Objective-C中每个类都是NSObject子类,因此每个对象都有一个内置的计数器,这个计数器称为引用计数(Reference Count),也称保留计数(Retain Count)。所谓Objective-C的内存管理,就是要维护引用计数器正确+1和-1,当引用计数器为0时,对象正确释放。在Objective-C中,每个对象就如同一个QQ讨论组,当有人创建讨论组时,讨论组人数为1(对象创建);每有一个人加入讨论组,该讨论组的人数+1(使用retain增加引用计数),每有一个人离开讨论组,该讨论组的人数-1(使用release减少引用计数);如果讨论组的人数为0,则自动解散
OC中管理内存的相关方法:
retain:增加对象的引用计数;
release:减少对象的引用计数
autorelease:在自动释放池块结束时候减少对象的引用计数
retainCount: 引用计数的数量;
注意:::一般都使用ARC模式不要随便使用MRC模式!!!
//ARC模式下要正确书写属性的修饰符
//和内存管理相关的属性修饰符是:
//strong -对象指针一般都使用strong,表示对引用计数+1(默认值)
//weak -
//1. 如果对象存在循环引用的(a关联b,b也关联a)a和b有一方必须使用weak破环
//2.一个对象的生命周期不由你自己的代码管理,也应该使用weak;
//3.如果属性是一个协议指针也应该使用weak;
//copy -
//1.确保NSString,NSarray,NSdectionary,NSData等
//不可变类型的指针的确指向一个不可变对象;
//2.如果属性是一个block类型的变量必须用copy;
//assign
//1.基本数据类型(就是非对象指针类型,包括结构体和枚举)都用assign
//整型,字符型,枚举,浮点型,结构体,联合体,实型;
//2.如果属性是对象指针,assign相当于weak;
//不要在C的结构体中使用对象指针。因为无法进行内存管理;
转载于:https://my.oschina.net/luhoney/blog/646236