OC知识点总结

1. 使用 #import 相对c的 include 是防止头文件的重复导入

2. NSLog 相对于 printf 会自动换行 显示当前时间与项目的基本信息

3.  OC中的对象方法用 - 开头表示  类方法用 + 开头表示, 对象方法只能通过对象来调用 也就是说 通过指针来调用  类方法只能通过类来调用

4. 使用对象方法,创建一个对象开辟一个存储空间   如果不想使用方法都需要创建对象开辟存储空间,可以把方法定义为类方法。   类方法不需要去创建存储空间 优化性能  

5. 对象方法可以直接访问属性(成员变量)类方法不可以

6. 类方法的优点 调用类方法的效率会比调用对象方法要高

7. 类方法和对象方法可以相互调用 对象方法可以直接调用类方法, 类方法中可以间接调用对象方法 

8. 创建对象: 1. 开辟存储空间 2. 初始化所有属性 3. 返回指针地址 

9. 存储空间 : 代码区  堆区 栈区  在堆区初始化对象 在栈区存放对象的地址

10. 创建对象的时候返回的地址其实就是类的第0个属性的地址  ,但是类的第0个属性其实是isa属性(自动创建)isa是一个指针,占八个字节

11. 类对象是系统帮我们创建的,里面保存了当前的所有方法,实例对象是我们通过new方法自己创建的。

12. 写在类声明的大括号中的变量,我们称之为成员变量(或者属性,实例变量),成员变量只能通过对象来访问,成员变量不能离开类,离开类之后就不是成员变量,成员变量不能再定义的时候进行初始化,  存储在堆里面,存储在堆中的数据,不会被自动释放,只能程序员手动释放

13.写在函数或者代码块中的变量,我们称之为局部变量,作用域:从定义的那一行开始,一直到遇到大括号或者return,作用域变量可以先定义在初始化,也可以定义的时候同时初始化, 存储在栈里面,  存储栈中的数据有一个特点,系统会自动给我们释放

14. 写在函数和大括号外部的变量,我们称之为全局变量,作用域:从定义的那一行开始,一直到文件末尾,局部变量可以先定义在初始化,也可以定义的同时初始化,存储在静态区中,程序一启动的时候就会分配存储空间,直到程序结束才释放. 存储在当前对象对应的存储空间中

15. 函数和方法的区别:函数属于整个文件,方法属于某一个类,方法只能通过对象或类调用, 函数可以直接调用,虽然函数属于整个文件,但是如果把函数写在类的声明中会不识别,不能把函数当做方法来调用,也不能把方法当做函数来调用

16. 方法:属性方法,类方法    方法可以没有声明只有实现, 方法也可以只有声明没有实现,第二种情况:编译时不会报错,运行会报错 unrecoginized selector sent to class'0x12132' 发送了一个不能识别的消息

17. 函数中不能直接访问成员变量, 成员变量和方法不能用static关键字修饰,不要和c语言混淆

18. 封装:屏蔽内部实现的细节,仅仅对外提供共有的方法/接口 好处:保证数据的安全性,对传入的数据进行隔离。一般情况下不会对外直接暴露成员变量,都会提供一些共有的方法进行复制,成员变量都被封装起来

19. 由于经常需要定义一些方法来操作成员变量,而每个方法都必须有一个有意义的名称,所有就有了getter-setter方法(为了取名方便)程序员的一种规范

20. setter方法的作用:设置成员变量的值,setter方法一定是对象方法,一定没有返回值,一定以set开头,并且set后面跟上需要设置的成员变量的名称去掉下划线,并且首字母大写,一定有参数(为成员变量设置set和get方法)

21. getter方法:获取成员变量的值,getter一定是对象方法,一定有返回值,而且返回值一定和获取的成员变量的类型一致,方法名称就是获取的成员变量的名称去掉下划线即可,一定没有参数

22. 成员变量以下划线开头的好处,就是可以用于区分局部变量和成员变量

23. 如果给属性提供了getter和setter方法,那么访问属性就可以用点语法进行访问了

24. 点语法的本质就是调用setter和getter方法,点语法是一个编译器的特性,会在程序编译成二进制的时候将点语法自动转化成setter和getter方法。

25. 如果点语法在等号左边,那么系统会自动转换成setter方法,如果点语法在等号右边,或者没有等号,那么编译器就会自动转换为getter方法

26. 点语法一般用于给成员变量赋值,如果不是给成员变量赋值一般情况下不建议使用,但也可以使用。

27.   self 会自动区分类方法和对象方法,如果在类方法中使用self调用对象 方法,那么会直接报错。

28. super 是编译器的指令符号,如果调用父类的方法的时候为了避免多余代码   用super去调用父类的方法。。。。如果想在子类中调用父类的方法用super  ,  如果用self会先在子类中去找,如果出现和父类的方法重名,会出现死循环。super应用环境:已经重写父类的方法,想保留父类的功能。

29. 程序中多态:父类指针指向子类的对象,没有继承就没有多态。 多态指一种事物的多种表现形态。多态具有动态类型,在编译的时候编译器只会检查当前类型对应的类中有没有需要调用的方法,在运行时,系统会自动判断真实类型。 如果想调用子类特有的方法必须强制类型转换为子类才能调用。优点:提高了代码的扩展性。

30. 实例变量修饰符:

@public 1. 可以在其他类中访问被public修饰的成员变量 2. 也可以在本类中访问被public修饰的成员变量 3. 可以在子类中访问父类别public修饰的成员变量

@private 1. 不可以在其他类中访问被private修饰的成员变量 2. 可以在本类中访问被private修饰的成员变量 3.不可以在子类中访问父类别private修饰的成员变量

@protected 1. 不可以在其他类中访问被protected修饰的成员变量 2. 可以在本类中访问被protected修饰的成员变量 3.可以在子类中访问父类别private修饰的成员变量

@package 介于public与private之间的,如果是在其他包中访问那么就是就是private的,如果实在当前代码所在的包中访问就是public的

实例变量修饰符作用域:从出现的位置开始,一直直到下一个修饰符出现,如果没有遇到下一个实例变量修饰符,那么就是修饰后面所有的实例变量。

31. %@是用来打印对象的,其实是用于打印字符串。(打印一个类,和一个对象的地址)只要给类发送class消息,就会返回当前类的类对象 

32. 只要利用%@打印某个对象,系统内部默认就会调用父类的description减号方法,调用该方法,该方法会返回一个字符串,字符串的默认格式 <类的名称:对象的地址>   用%@打印某个类,就会调用父类的(nsobject)的加号开头的description  两种情况都可以重新父类的description方法。如果通过%@打印对象,就会调用减号开头的,如果通过%@打印类就会调用加号开头的。

33. self写在对象方法中就代表当前调用该方法的对象。访问属性的三种方法:1. p.age 2. p->age 3. [p age];

34. 在description方法中尽量不要使用self来获取成员变量,因为如果你经常在description方法中使用self可能不小心就写成了%@,self        如果在description方法中利用%@输出self会造成死循环。

35. 私有变量和私有方法{

实例变量(成员变量)既可以在@interface中定义,也可以在@implementation中定义,写在@implementation中定义的默认就是私有变量被@private修饰,并且在其他类中无法查看,  在interface中定义的在其他类中都可以查看,只不过有的不可以进行操作而已。

在OC中没有真正的私有方法,因为OC是消息机制。

}

36. @property: 是一个编译器指令,告诉xcode需要执行什么命令,用property替换一些代码 ,在xcode4.4之前,可以使用@property来代替getter/setter方法的声明,也就是说我们只需要写上@property就不要写getter/setter方法的色。  编译器只要看到@property就知道我们要生成一个属性getter/setter的方法的声明 @property int age 用这种格式来替换age的set和get方法

37. @synthesize基本使用:是一个编译器指令,它可以简化我们getter/setter方法的实现。实现在声明后面写上大括号代表被实现. 1.在@synthesize age;后面告诉编译器,需要实现哪一个@property生成的声明。2. 告诉synthesize,需要将传入的值赋值给谁和返回的值给使用者 @synthesize age = _age; 如果@synthesize age;是这种形式的赋值,则系统 默认会赋值给和@synthesize后面写的名称相同的成员变量. 但是@property会默认赋值给_age带有下滑线的age.

38. 在xcode4.4之后,对@property进行了增强。只要利用一个@property就可以同时生成setter/getter的声明和实现  .  @property会默认赋值给_age带有下滑线的age. @property有一个弊端,它只会生成最简单的getter/setter方法,不会对传入的值进行判断.如果想对传入的数据进行过滤,那么我们就必须重写getter/setter方法。 如果重写setter方法,那么property就只会生成getter方法,如果重写了getter方法,那么property就只会生成setter方法。@property自动帮我们生成的成员变量是一个私有的成员变量(_age),也就是说在.m中生成的,而不是在.h中生成的。如果重写了setter/getter方法,那么property就不会自动帮我们生成私有的成员变量,下划线开头的age.(举例age).

39. property修饰符:{

如果给一个属性提供了getter/setter方法,那么我们称这个属性为可读可写属性,如果只提供了getter方法,那么成这个属性为只读属性,如果只提供了setter方法,那么我们称这个属性为只写属性,如果都没有提供,那么我们称这个属性为一个私有属性。

readonly 不生成setter方法,只生成getter方法,readwrite既生成setter方法,有生成getter方法。

格式:@property(属性修饰符) 数据类型 变量名称;默认修饰符readwrite

自定义getter方法名称:

@property(getter = abc)int height;

}

readonly为只读属性,如果想修改其值, 这个时候我们可以用KVC来给声明为readonly的属性重新赋值。 

[对象 setValue:"value" forKey:NSStringFromSelector(@selector("属性名"))];

/// 就会变成新值

nslog(@"%@",对象.属性名);

40. id 数据类型:是一个动态数据类型。

默认情况下所有的数据类型都是静态数据类型,静态数据类型的特点:在编译时就知道变量的类型,知道变量中有哪些属性和方法。在编译的时候就可以访问这些属性和方法,并且如果是通过静态数据类型定义变量,如果访问了不属于静态数据类型的属性和方法,那么编译器就会报错。

动态类型的特点: 在编译的时候编译器并不知道变量的真实类型,只有在运行的时候才知道他们的真实类型,并且如果通过动态数据类型定义变量,如果访问了不属于这种数据动态类型的方法和属性,编译器不会报错.

id 相当于 id = NSObject *    属于万能指针。他们两个的区别:id是动态类型,NSObject属于静态类型。通过静态数据类型定义变量,不能调用子类特有的方法,通过动态数据类型定义变量,可以调用子类特有的方法。  通过动态数据类型定义的变量,可以调用私有的方法。

弊端:由于动态数据类型可以调用任意方法,所以可能调用不属于自己的方法,而编译时又不会报错,所以可能导致运行时错误。id 一般用于多态。可以减少代码量,避免调用子类特有的需要强制转换。为了避免数据类型引发的运行时的错误,一般情况下如果使用动态数据类型定义一个变量,在调用这个变量的方法之前会进行一次判断,判断当前变量是否能够调用这个方法。(使用iskindOfClass:【NSObject class】进行判断)isMemberOfClass 也可以   两者的区别:isKindOfClass 用于判断是否属于本类或子类   isMemberOfClass 只用于判断是否属于本类。

[Student isSubClassOfClass:[Person class]]  用于判断 student是否是person子类

41. new方法 1.开辟存储空间(调用+alloc方法)   2.初始化所有的属性 调用-init 方法(成员变量)3. 返回对象的地址  new 相当于【alloc init】

alloc做了什么事情:1. 开辟存储空间 2. 将所有的属性设置为0    3. 返回当前实例变量的地址   init做的事情:1. 初始化成员变量,但是默认情况下init的实现是什么都没有做. 2. 返回初始化后的实例对象地址。

注意:alloc和init返回的存储空间是同一个  打印地址 %p 

42. 构造方法:init开头的方法。用于初始化一个对象,让某个对象一创建出来就拥有某些属性和值。重写init方法,在init方法中初始化成员变量,注意:重写init方法必须按照苹果规定的格式重写,如果不按照规定会引发一些位置的错误。-(instancetype)init{_age = 10}

苹果固定格式:1.不能先初始化父类,在初始化子类 2. 必须判断父类是否初始化成功,只有父类初始化成功才能继续初始化子类 3. 返回当前的地址

-(instancetype)init{

self = [super init];//初始化父类,只要父类初始化成功,就会返回对应的地址,如果初始化失败,就会返回nil==0==假==初始化失败

         if(self != nil){//判断是否初始化成功

                //初始化子类,        设置初始化的值

           _age = 10;

      }

      //返回地址

    return self;

}

43. instancetype和id的区别:他们都是万能指针,指向一个对象,但是,instancetype在编译的时候能判断这个对象是什么类型,id在编译的时候不能判断对象的真是类型。另外一个区别:id可以用来定义变量,可以作为形参,可以作为返回值,而instancetype只能作为返回值。  自定义构造方法,尽量使用instancetype,在编译的时候就能检查错误

44. 自定义构造方法:其实就是自定义一个init方法。   一定是对象方法,一定返回id或者instancetype ,一定以init开头

-(instancetype)initWithAge:(int)age{if[self = [super init]] _age = age; return self;}(With的W必须要大写)

一个类可以有0个或多个自定义构造方法。

自定义构造方法的继承。  在子类中super 父类的init方法   属性名称不要以new开头,方法名也是。

45. 类工厂方法(也称快速创建方法):类工厂方法是一种用于分配,初始化实例并返回一个它自己的实例的方法,类工厂方法很方便,因为他们允许您只使用一个步骤就能创建对象   。   例如:new

自定义类工厂方法:1,一定是+号开头 2,返回值一般是instancetype类型或id 3,方法名称以类名开头,首字母小写。

+(instancetype)persionWithAge:(int)age

{

Persion *p = [[Person alloc]init];  p.age = age;    return p;//注意:在类工厂方法中一定不要使用类名来创建对象,要使用self来创建对象。self在方法中就代表类对象  Persion *p = [[self alloc]init];

}

类的本质:类其实也是一个对象,这个对象会在这个类第一次被使用的时候创建,只要有了类对象,将来就可以通过类对象来创建实力对象,实例对象中有一个isa指针,指向创建自己的类对象。  类对象中保存了当前所有的对象方法,当给一个实力对象方法消息的时候,会根据实例对象中的isa指针去对应的类对象中查找。类对象代表类,Class类型,对象方法属于类对象   如果详细的接收者是类名,则类名代表类对象,所有类的实例都由类对象生成。

获取类对象:Class c = [对象/实例对象 class];//一个类在内存中只有一份类对象。

类对象的使用场景:【c alloc】init];[c text];

1. 用于创建实例对象,2,用于调用类方法。

46. 只要程序启动就会将类的代码加载到内存中,放到代码区。  load方法会在当前类被加载到内存的时候调用,有且仅会调用一次     会自动被调用

47. +(void)initialize{} 当前类第一次被使用的时候就会调用(创建类对象的时候)只会被调用一次

48. SEL 类型作用,配合对象类来检查对象或类中有没有实现某一个方法

SEL sel = @selector(text);

BOOL flag = [Person respondsToSelector:sel];//对用类方法

Person *p = [Person new];   BOOL flag = [p respondsToSelector:sel];//调用类方法

49. 内存管理:创建一个对象,定义一个变量,调用一个函数或方法,都会增加app的内存占用。   所谓内存管理就是分配内存(增加内存占用)和清除内存(减小内存占用)

内存管理的范围:任何继承了NSObject的对象,对其他非对象类型无效(char,float,double,struct,enum等)

只有oc对象才需要进行内存管理的本质原因:oc对象存储于堆里面   非oc对象一般放在栈里面(栈内存会被系统自动回收)

50. dealloc  重写dealloc,在这里释放相关资源,  一旦重写了dealloc就必须调用【super dealloc】,并且放在写在代码最后.    

注意:不能直接调用dealloc方法,一旦对象被回收了,它占用的内存就不在可用,坚持使用会导致程序崩溃(出现野指针错误)

51. 在ARC模式下是编译器帮你释放内存的 java是系统帮你清理内存的  一个引用计数器占用4个字节

52. 野指针和空指针:

只要一个对象被释放了,我们就称为僵尸对象,称这个指针为野指针,只要给一个野指针发送消息就会报错。(用栈区中的指针去访问堆区中的对象就会崩溃  ,  找不到可以使用的对象)一般情况下,在对象被释放后,会把指针设置为空指针,给空指针发送一个消息不会崩溃、(nil  0)   p = nil;

53. 分类是用于给原有类添加方法的,不能添加属性  ,  分类中的@property  只会生成setter、getter方法的声明,不会生成实现以及私有的成员变量  ,  可以在分类中访问原有类的.h中的属性

54. 类扩展:类扩展是分类的一个特例,  对比分类来说,就少了一个分类名称,因此也有人称他为“匿名分类”  extension

55. property修饰符:retain会自动帮我们生成set方法内存管理的代码, assign:不会帮我们生成set方法内存管理的代码,仅仅只会生成普通的getter/setter方法,默认什么都不会就是assgin.    相同类型的修饰符不能再一起使用  比如retain和assign

atomic  和 nonatomic 用于多线程中  ,atomic性能低,nonatomic性能高一般情况下不会用atomic。   在ios开发中,只要写property  后面就跟上nonatomic   来提高性能。

56. @class  和 @“import”  的区别:

由于import是一个预编译指令,他会将“”中的文件拷贝到import所在的位置,并且import有一个特点,只有“”中的文件发生了变化,那么import就会重新拷贝一次(做更新操作)  @class仅仅是告诉编译器,有一个这个类,不会做任何的拷贝操作。  注意:由于@class仅仅是告诉编译器后面的名称就是一个类,所以编译器并不知道这个类中有哪些属性和方法,所以在.m中使用类的使用,需要import这个类才可以使用哦.  相互使用类的时候,可以用@class(避免相互拷贝,产生报错)

57. block  用来保存一段代码  block是一个变量,  是变量结尾就要有;结束符号

block注意事项:1.block中可以访问外面的变量。2,block中可以定义和外界同名的变量,并且如果在block中定义了和外界同名的变量,在block中访问的是block中的变量,3,默认情况下,不可以在block中修改外界变量的值,因为blcok中的变量那个和外界的变量并不是同一个变量,如果block中访问到了外界的变量,block会将外界的变量拷贝一份到堆内存中。 因为block中使用的外界变量是copy的,所以在调用之前修改外界变量的值,不会影响到block中copy的值。  如果想在block中修改外界变量的值,必须在外界变量前面加上__block ,加完之后,如果在block中修改变量的值,会影响外界变量的值。内外部的两个变量的地址是不一样的,只是指针之间值得传递。

为什么不加__block就不能修改外界变量的值,为什么加了之后就可以修改外面的值:加上就是地址传递,所以可以在block中修改外界变量的值,不加的话是值传递;。

默认情况下block存储在栈中,如果对block进行一个copy操作,block会转移到堆中,如果block在栈中,block中访问了外界的对象,那么不会对对象进行retain操作,  但是如果block在堆中,  block中访问了外界的对象,那么会对外界的对象进行一次retain。

58. Protocol  协议:是用来创建方法的,只有方法的声明,没有方法的实现。

协议和继承的区别:1.继承之后默认就有实现,而protocol只有声明没有实现。 2.相同类型可以使用继承,但是不同而理性的类只能使用protocol。3.protocol可以用于存储方法的声明,可以将多个类中共同的方法抽取出来,以后让这些类遵守协议方法即可。

父类遵守了某个协议,那么子类也会自动遵守这个协议。     在oc中一个类可以遵守一个或多个协议,oc中只能继承一个父类。 

OC中的协议有可以遵守其他协议,只要一个协议遵守了其他协议,那么这个协议中就会自动包含其他协议的声明。

NSObject是一个基类,任何其他类最终都要继承它  有一个NSObject的协议,它是一个基协议,最根本最基础的协议。

@required:被它修饰的协议方法必须实现,不实现编译器会发出警告

@optional:被它修饰的不一定要实现。

59. 协议的应用场景,可以将协议写在数据类型的右边,那么对象必须遵守某个协议。    例如:Person<Protecol> *p = [Person new];

声明属性的时候属性右边也可以使用。

在运用协议的时候,注意事项:虽然在接受某一个对象的时候,对这个对象进行了类型限定,限定它必须实现某个协议,但是并不意味着这个对象就真正的实现了该方法,所以每次在调用对象的协议方法时应该进行一次验证。例如:

if([self.wife respondsToSelector:@selector(cooking)]){

[self.wife cooking];//如果有这个方法,就执行里面的操作

}

60. 设计模式:设计模式是一套被反复使用,多数人知晓的,经过分类编目的,代码设计经验的总结,使用设计模式是为了可重用代码,让代码更容易被他人理解,保证代码的可靠性。

代理设计模式:比如我们买一包纸,不需要去制造厂去买,去超市去买,超市就是一种代理模式。

代理模式的应用场合:例如对象A和B,当A对象想监听B对象的一些变化时,可以使用代理设计模式,当B对象发生一些事情,想通知A对象的时候,可以使用代理设计模式。

协议的编写规范:1.一般情况下,当前协议属于谁,我们就将协议定义到谁的头文件中 2,协议的名称一般以他属于的那个类的类名开头,后面跟上protocol或者delegate 3,协议中的方法名称一般以协议的名称Protocol之前的作为开头 4,一般情况下,协议中的方法,会将出发该协议的对象传递出去 5、一般情况下,一个类中的代理属于的名称叫做 delegate 6、当有一个类中要称为另外一个类的代理的时候,一般情况下在.h中用@protocol协议名称,告诉当前类这是一个协议   在.m中用#import导入一个协议的声明

61. Fundation简介

框架:众多应用程序的结合,框架是由许多类,方法,函数,文档在按照一定的逻辑组织起来的集合,以便使研发程序变得更容易。在OSX下mac大概有80个框架为所有程序开发奠定基础的框架称为Fondation框架。

Fundation框架中大约有125个可用的头文件。是其他框架开发的基础,包含了许多常用的数据类型:结构体,枚举,类。

Fundation框架中的类都是以NS为前缀(Next Step的缩写  是85年乔布斯离开苹果公司创立的NeXT公司)这个框架是以前在NeXT公司写NeXT的框架。

对电脑文件显隐:defaults write com.apple.finder AppleShowAllFiles -bool True   在终端中进行显示和隐藏的操作 ,  操作后一定要重新启动Finder

62. 字符串基本概念:

创建字符串的方法:1.通过字符串常亮创建 2,通过alloc init创建 3,通过类工厂方法创建/ stringWithFormart   不同的创建方法所存储的位置不一样   第一种存储在常量去  下面两种存储在堆区

但是如果是通过alloc initWithString方法除外,因为这个方法是通过copy返回一个字符串对象给我们,而copy又分为深拷贝和浅拷贝,如果是深拷贝会创建一个新的对象,如果是浅拷贝不会创建一个新的对象,而是直接返回被拷贝的对象的地址给我们,二initWithString正好是浅拷贝,所以无论是在什么平台,什么编译器都是指向同一块存储空间。

63. 字符串的读取和写入:

1、NSString *str = [NSString stringWithContentOfFile:path encoding:NSUTF8StringEncoding error:&error];

2、BOOL flag = [str writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];

64. 分类是用于给所有类添加方法的,他只能添加方法,不能添加属性(成员变量),分类中的@property,只会生成setter/getter方法的声明,不会生成实现以及私有的成员变量。可以在分类中原有类中.h中的属性

65. 对url的读写,如果url中有中文,需要用【NSURL fileURLWithPath:@"fsfsd"】;进行编码读写

66. 字符串进行比较:str isEqualToString:str2   或者  str == str2   前者是比较内容是否相等,后者是比较地址手否相同。

第三种方法用switch进行判断:

str compare: str2   有三种结果,是一个枚举值,NSOrderAscending   NSOrderedSame   NSOrderedDescending   升序   相等  降序  另外一种方法是忽略大小写就行比较的  caseInsensitveCompare  和第三种方法 比较的方法是一样的。

67. 字符串搜索:判断以什么开头,判断以什么结尾  hasPrefix   hasSuffix   .    还有一个字符串包含:rangeOfString:返回值是NSRange  这个包含字符串的起始位置和长度,如果没有要查询的结果,返回的长度为0,字符串的其实位置为NSNotFound

68. 只要是OC提供的结构体一般都是NSMakeXXX      {x,x }  

int和NSInteger其实是差不多的,但更推荐使用NSInteger,因为使用NSInteger,这样就不用考虑设备是32位还是64位了。

NSUInteger是无符号的,即没有负数,NSInteger是有符号的,所以NSUInteger类型不能给它赋负值。比如for循环的时候,a=-1的时候,是能进入循环的。

69. 字符串截取:1.动态获取截取的起始位置,2,动态获取截取的长度 。  

str = @"<head>麦迪文</head>";

NSUInteger location = [str rangeOfString:@">"].location + 1;

NSUInteger length = [str rangeOfString:@"<" options:NSBackwardSearch].location - location;//从字符串后面往前找

NSRange range = NSmakeRange(location,length);

70. 字符串截取:【str stringByReplacingOccurrencesOfString:@"xx"】;

替换首位:str = @"sfdsfdsfdsf";

NSCharacterSet *set = [NSCharacterSet whitespaceCharacterSet]; 

newStr = [str stringByTrimmingChatactersInSet:set];

71. 字符串转换:【str uppercaseString】转换成大写   【str lowercaseString】转换成小写;

将字符串首字母转换为大写   【str capitalizedString】;

【str deleteCharactersInRange:range】;//删除指定的字符串

72. NSMutableString: 继承于NSString   

对于不可变字符串,每次改变内容的时候都是创建一个新的对象。地址会改变

可变字符串:每次修改都是添加到同一个地址位置。

73. NSArray  

NSArray *arr = [NSArray arrayWithObject:@"2",@"2",nil];//nil  是一个结束符

快速创建数组:NSArray *arr = @[@“1”,@“3”]; // 和上面的意义一样

查找数组中是否包含了某一个元素  

【arr containsObject:@"33"】;//返回值布尔值

oc中经常使用的三种遍历:1.for循环的基本遍历 2.forin遍历 (for循环的增强版)3. 利用oc数组的迭代器遍历也就是block遍历

[arr enumerateObjectsUseingBlock:........];//返回值有三个参数:1,元素(obj),2,索引(idx) 3,*stop (用于控制循环停止在某一个地方)

如果使用oc数组存储对象,可以调用oc数组的方法让数组中所有的元素都执行指定的方法

【arr makeObjectPerformSelector:@selector(say)】;//say是一个对象或者类方法

makeObjectPerformSelector:@selector(say:) withObject:@"ss"】;//需要传递给调用方法的参数

注意点:如果数组中保存的不是相同类型的数据,并且没有相同的方法,那么会报错.

对数组进行排序:[arr sortArrayUsingSelector:@selector(compare:)];


//注意:想使用compare方法对数组中的元素进行排序,那么数组中的元素必须是Fondation框架中的对象,也就是说不能是自定义的对象。

如果想调用自定义对象:需要使用

【arr sortedArrayWithOptions:NSSortStable usingComparator:....】;

返回obj1和obj2对象  进行比较  return obj1>obj2  或者相反

&&&&&&&冒泡排序

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"12",@"84", @"35", @"70", @"85", @"99", nil];

NSInteger count = [array count];

for (int i = 0; i < count; i++) {

for (int j = 0; j < count - i - 1; j++) {

// if ([[array objectAtIndex:j] intValue] > [[array objectAtIndex:(j + 1)] intValue]) {  //这里在用[array objectAtIndex:j]时候必须intValue

//                if([[array objectAtIndex:j] compare:[array objectAtIndex:j + 1]] == -1){  //这里整体必须有一个返回值,-1,0,1,因为compare的返回值NSComparisonResult是一个枚举类型的值,所以要返回一个值

if([[array objectAtIndex:j] compare:[array objectAtIndex:j + 1] options:NSNumericSearch] == 1){  //同上potions  NSNumericSearch = 64,

[array exchangeObjectAtIndex:j withObjectAtIndex:(j + 1)];  //这里可以用exchangeObjectAtIndex:方法来交换两个位置的数组元素。

}

}

}

for (NSString *i in array) {

NSLog(@"%@", i);

}

74. NSArray和NSString转换

将数组中的元素进行连接起来:【arr compontentsJoinedByString:@"-"】;

通过一个字符串生成一个数组:也叫作字符串切割

str = @"33*44*55*56";

[str componentSwparatedByString:@"*"];

75. NSArray文件读写:

arr = @[@"2",@"3"];

BOOL flag = [arr writeToFile:@"路径.plist" atomically:YES];//将数组写入到文件中,其实如果讲一个数组写入到文件中会后,本质是戏写入了一个XML文件  ,  在iOS开发中一般情况下我们会将XML文件的扩展名保存为plist

从文件中读取一个数组:

arr = [NSArray arrayWithContentOfFile:@"路径"];

注意:write方法只能写入数组中保存的元素都是Fundation中的方法,不能写入自定义的元素。

76. NSMutableArray:

其实可变的数组,字符串,字典都是不可变数组,字符串,字典的子类。

注意:不能通过@【】来创建一个可变数组,因为用@【】创建出来的是一个不可变的数组,如果把一个不可变数组当做一个可变数组开使用,会引发一个运行时的错误。

77. NSDictionary:

对字典进行forIn遍历  对打印出所有的key

最方便的遍历使用block进行遍历

字典保存的数据是无序的

78. NSMutableDictionary:

不能使用@{}来创建可变字典  如果是不可变数组,那么key不能相同

NSArray是通过下标来访问元素,NSDictionary是通过key值来访问元素(因为它是无序的)

79. 常用结构体:

NSPoint和CGPoint NSSize和CGSize NSRect和CGRect  这三个结构体是OC中常用的。这是三个结构体,只是有三个别名。

在苹果开发中,苹果推荐我们使用CG开头的结构体,也就是说NS开头的结构体一般不用.

80. NSNumber:

数组和字典都只能存放对象类型的数据,基本数据类型存放会报错。如果想存储基本数据类型,需要将基本数据转换成对象类型:

例如: NSNumber *num = [NSNumber numberWithInt:age];   或者使用快速转换的方法:NSNumber *num = @(int);  如果传入的是常量则不需要使用圆括号。

81. NSValue:

NSValue是NSNumber的父类

如果想包装基本数据类型以外的类型,可以使用NSValue。   NSValue中有很多方法,比如可以转换常用的基本结构体,如果想转换自定义结构体可以使用:

NSValue *value = [NSValue valueWithBytes:&p objCType:@encode(Person)];//Person是自定义的结构体    &p是传入的指针 @encode是把自定义结构体对象转化成指针。  如果想获取自定义结构体中的变量:【value getValue:&p】;//Person *p;

82. NSDate:

NSDate *now = [NSDate date];//获取当前的时间

NSTimeZone *zone = [NSTimeZone systemTimeZone];  //获取当前所处的时区

NSInteger seconds = [NSInteger secondsFromGMTForDate:now];//获取当前时区和指定时间的时间差

NSDate *newDate = [now dateByAddingInterval:seconds];//在now的基础上增加了多少秒

newDate就是获取的当前时区的正确时间。

时间格式化:NSDateFormatter 

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];

formatter.dataFormatter = @"yyyy年MM月dd日 HH时mm分ss秒 z";

formatter.dataFormatter = @"yyyy-MM-dd HH-mm-ss";

利用时间格式化对象对时间进行格式化:

NSString *str = [formatter stringFromDate:[NSdate date]];

//注意: 如果是从NSString格式化为NSDate,那么dateFormat的格式,必须和字符串中的时间格式一致,否则可能转化失败。

NSString *str = @"2016-12-12 07:30:20";

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];

formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";

NSDate *date = [foramtter dateFormString:str];

83. NSCalendar:

NSDate *now = [NSDate date];

NSCalendar *calendar = [NSCalendar currentCalendar];

NSCalendarUnit type = NSCalendarUnitYear | NSCalendarMonth;

NSDateComponents cmps = [calendar components:type formDate:now];

nslog(@"%@%@",cmps,year,cmps.month);

比较两个时间:

NSDateComponents *cmps = [calendar components:type fromDate:date toDate:now options:0];

84. NSFileManager:

NSFileManager *manager = [NSFileManager  defauleManager];

BOOL flag = [manager fileExistsAtPath:@""];//判断一个文件或者文件夹是否存在

BOOL dir = NO;//默认为NO

BOOL flag = [manager fileExistsAtPath:@"" isDirectory:$dir];//判断一个文件是否存在,并且判断它是否是一个文件夹,  第一个参数是路径,第二个参数返回的是判断这个路径是否是一个文件夹。

获取文件或文件夹的属性:

[manager attributesOfItemAtPath:@"" error:nil];

获取文件夹中所有的文件

【manager contentsOfDirectoryAtPath:@"" error:nil】;

也可以创建文件夹和文件方法,自己去找createFile.........

85. 集合中对象的内存管理

1.如果将一个对象添加到一个数组中,那么数组会对对象进行一个retain   

2. 当数组对象释放之后,会给数组中所有的对象发送一条release消息

3. 当数组移除一个对象之后,会给这个对象发送一条release消息

86. copy 基本使用:

NSString *str = @"uio";

NSMutableString *copy = [str mutableCopy];

只要是拷贝出来的对象,拷贝出来的对象中的内容一致,一般情况下拷贝会生成一个新的对象,为什么会产生一个新的对象(因为拷贝要求修改原来的对象,不能影响到拷贝出来的对象   修改拷贝出来的对象也不能影响到原来的对象,所以需要生成一个新的对象  由于以前的对象是一个不可变的对象,而通过nutableCopy拷贝出来的对象必须是一个可变的对象,所以必须生成一个新的对象)

如果通过不可变对象调用了copy方法,那么不会生成一个新的对象,原因:(因为原来的对象是不能修改的,拷贝出来的对象也是不能修改的,既然两个都不能修改,所以永远不能影响到另一个对象,那么已经符合需求,所以OC为了对内存进行优化,就不会生成一个新的对象)

正是因为调用copy方法:有时候会生成一个新的对象,有时候不会生成一个新的对象,所以:如果没有生成新的对象,我们称之为浅拷贝,本质就是指针拷贝。如果生成了新的对象,我们称之为深拷贝,本质就是会创建一个新的对象。

对于内存的管理:  如果是浅拷贝:不会生成新的对象,但是系统就会对原来的对象进行retain,所以需要对原来的对象进行一次release。   如果是深拷贝:会生成新的对象,系统不会对原来的对象进行retain,但是因为生成了新的对象,所以我们需要对新的对象进行release

87.  对于property中的修饰符,如果修饰字符串的话,就用copy避免了修改原对象或新对象的值影响被拷贝对象中的内容,如果用retain进行修饰的话,修改了一个对象就会对原对象或者新对象的内容产生影响。

88. copy的用途:1.防止外界修改内部的数据。2. block默认存储在栈中,栈中的block访问到了外界的对象,不会对对象进行retain,block如果在堆中,如果在block中访问了外界的对象,会对外界的对象进行一次retain。 使用Block_copy(myBlock),就是将block转移到堆中。   3.如果使用copy保存block,这样可以保住block中使用的外界对象的命,避免以后调用block的时候,外界的对象已经释放了。

89. copy block之后引发循环引用  如果对象中的block又用到了对象自己,那么为了避免内存泄漏,应该讲对象修饰为__block

90. 自定义类实现Copy(让自定义的对象能够被copy)

1. 需要遵守NSCopying协议

2. 需要实现协议方法:-(id)copyWithZone:(NSZone *)zone{  };

91. 单例:

由于所有的创建方法都会调用allocWithZone:,所以只需要在该方法中控制当前对象值创建一次即可。

设置一个静态的对象  。   使用代理每次创建对象的时候都是同一个地址。相当于永远之创建同一个对象。   只有程序销毁的时候,这块对象才会被释放。

\  表示换行

单例的优缺点:

单例模式的优缺点

1、时间和空间

比较上面两种写法:懒汉式是典型的时间换空间,也就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存空间。

饿汉式是典型的空间换时间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断了,节省了运行时间。

2、线程安全

(1)从线程安全性上讲,不加同步的懒汉式是线程不安全的,比如,有两个线程,一个是线程A,一个是线程B,它们同时调用getInstance方法,那就可能导致并发问题。如下示例:

public static  Singleton getInstance(){

if(instance == null){

instance = new Singleton();

}

return instance;

}

程序继续运行,两个线程都向前走了一步,如下:

public static  Singleton getInstance(){

if(instance == null){

instance = new Singleton();

}

return instance;

}

推荐阅读更多精彩内容