iOS开发入门知识点总结

Objective-C

一门动态语言,动态两个字主要就体现在我们调用方法的时候,运行时回动态的查找方法,然后调用相应的函数地址。运行时是整个Objective-c程序的基石,有了它我们的程序才能正常运行起来。

NSObject是Cocoa中绝大部分类的基类,它主要是提供了序列话,拷贝对象,以及支持运行时动态识别的框架。

另外,在OC中,一切皆为指针。

在Objective-c中每一个类对象最开始的位置都会有一个isa指针,该指针指向一块内存区域,该部分主要包含两部分信息:

  1、指向父类的指针。

  2、自身的方法分发表。

当我们调用一个对象的某一个方法的时候,首先会在当前类的分发表中寻找该方法,如果找不到对应的方法,然后再去其父类中寻找该方法,依次类推直到找到对应的方法为止

流程图如下 

  你可能会想到,如果一个类有很深的继承层次,每次去调用根类的某个函数,岂不是都要做很多次查找。理论上是这个样子的,不过runtime也并非那么傻,它会为每一个类(不是对象)维护一个经常调用的方法的列表,只要调用过就会缓存起来(官方没有明确说明缓存机制),这样当程序运行稳定以后整个方法调用的过程就会更加高效。

本文不详细介绍OC的基本语法等内容:

OC基础数据类型:http://www.cnblogs.com/GISerYang/tag/Objective-C/ 

 

Cocoa框架

Cocoa提供了用于存放数字和字符串的通用数据类型的实际的类。非正式地可以将这些称为值类或基本值类。

Cocoa框架本身封装了三个独立的框架:Foundation基本框架、AppKit框架和核心数据框架

Foundation Framework

  提供基本的构建块类,如字符串、数组、数值、文件访问等。可以在Mac和iPhone OS(iPhone、iPod touch和iPad上使用的系统)上使用此框架。Foundation类会使得更容易处理国际文本和数字,使得程序员从大量繁杂细节中解脱出来。

AppKit Framework

  提供具体地处理用户接口元素(例如,窗口、控制和字体等)的框架。AppKit框架在Mac上的功能与iPhone OS上的UIKit功能相同,都是围绕相同的概念创建的。

Core Data Framework

  提供数据存储、数据建模和自动改变操作轨迹(也称为自动回复或重做)。可以使用SQLite、XML、binary存储类型存放数据,或者甚至可以创建自己的存储类型。

 

非正式协议或类 @interface与@implementation到@end

@interface与@end间所做的声明,是约定要实现里面的方法,但是.m文件@implementation到@end间不实现也不会编译出错。

所以这种君子协定相对协议@protocol来说就是一种非正式协议。

换一种理解方式,interface和implementation共同代表一个类,即oc中的类必须包括两部分,interface部分和implementation部分;

将成员变量和成员方法的声明部分放置在interface部分中,包括继承关系,protocal实现关系,都在interface里面的头部进行声明;

实现部分放置在implementation部分中,相当于是将类拆分成声明和实现两部分,这两部分缺一不可。

@interface PropertyModel : NSObject{  
    NSString* sex;  //无修饰,默认的protect属性只允许本类和子类访问.
    @public NSString* name; //所有类都能访问,访问方式为指针->.  
    @private NSString* classes;  //私有的只有本类能访问.
}  
@property(nonatomic,copy)NSString* sexName;  //通过self.sexName即可访问.
@end  

方法前都以‘-’减号开始(OC不区分public与private),相对如果是‘+’加号,表示是静态成员。 

- (方法返回值的数据类型) 函数名: (参数1数据类型) 参数1的变量名 参数2的备注名字: (参数2数据类型) 参数2值的变量名 …. ;

注:可见OC方法除了第一个参数变量,每一个变量要有一个备注名字,调用语法与此类似。

 

公共属性 @property

一个类中的变量在@interface :NSObject{} 的括号中声明,而在 @interface : NSObject{}括号之后@end之前,也可以用 @property 去定义变量。

@interface中定义变量的话,你所定义的变量只能在当前的类中访问,在其他类中是访问不了的。

如果想方便的使用“self.变量名”的点访问方式去读写变量,并且类外也可以访问,那么变量就要被设置为类的属性。

 

@property 预编译指令的作用是自动在.h文件中声明属性的setter和getter方法。

@sythesize 创建了该属性的访问代码,编译器将添加实现 -setRainHandling:和-rainHandling方法的预编译代码。

@dynamic 当企图调用不存在的getter和setter方法,你将会得到一个错误。

格式:

    @property (属性) 数据类型 *name;

在.h中用@property指明属性,在.m中用@synthesize表明生成相应的访问器。

属性的扩展

  • assign //简单赋值,主要用于基本数据类型
  • copy //创建一个新的对象,新的对象和旧对象是独立的两个对象
  • retain //将对象计数器加1
  • readonly //表示只读属性  只会生成getter方法 不会生成setter方法
  • readwrite //默认值,表求生成setter和getter方法
  • nonatomic //非原子访问,不加同步 ,多线程并发访问提高性能 (对多线程的保护,防止在未写完,被另一个线程读取,造成数据错误)

 

协议Protocol:用协议实现委托

相当于是C++中的纯虚基类,在写java的时候都会有接口interface这个概念,接口就是一堆方法的声明没有实现,而在OC里面,Interface是一个

类的头文件的声明,并不是真正意义上的接口的意思,在OC中,接口是由一个叫做协议的protocol来实现的。这个里面

可以声明一些方法,和java不同的是,它可以声明一些必须实现的方法和选择实现的方法。这个和java是完全不同的。

@optional和@required   可以理解为虚函数和纯虚函数。

委托本来的实现方法是,若B想让A做事,让B做老大则在B类中声明一个A的实例作为成员变量,这样B就可以调到A的方法;但是OC中采用另一种反向思维模式,B想委托A做事让A做老大,在A中实例B,再设置实例B的一个指针指向A自己,B中用这个指针来调用A的函数,而这些被需要的函数就是通过B的协议让A遵守来实现。

MyProtocol.h来声明协议接口:只声明方法,不做具体实现

#import <Foundation/Foundation.h>
@protocol MyProtocol <NSObject>

@optional
//这个方法是可选的
- (void) print:(int) value;

@required
//这个方法是必须实现的
- (int) printValue:(int) value1 andValue:(int) value2;

@end

则引用MyProtocol协议的类必须按要求实现协议的方法

#import <Foundation/Foundation.h>
#import "MyProtocol.h"

@interface MyTest : NSObject <MyProtocol>

- (void) showInfo;

@end

下面举个例子:

当A view 里面触发打开B view(B是A的一个模态视图),而B view需要反馈修改A view的界面,那么这个时候B就需要用到委托了。

 

在B中声明一个与委托人的协议,和一个委托人指针。某类遵守了这个协议,就要按要求实现这些函数,实现A的实例并将B的委托人指针指向自己,供B来通过指针调用。

在B中可以通过函数 [委托人指针 respondsToSelector:@selector(函数名:)]来检查委托人是否实现了某个函数。

A_View.h:
@interface:UIViewController<B_ViewDelegate>
{
        B_View *myB_View;
}
@end
A_View.m:
- (void)viewWillAppear:(BOOL)animated  
{  
        myB_View.touchDelegate = self; //将委托 ,这里可以看出委托其实也可以理解为B_View中的一个属性 
        [self.view addSubview: myB_View];  
}  
- (void)ontouch:(id)sender
{  
   //实现协议B_ViewDelegate的ontouch方法供B调用修改A
}
B_View.h:
@protocol  B_ViewDelegate<NSObject>
@optional 
-(void)touch:(id)sender;
@end

@interface  B_View:UIViewController
{}
@property(nonatomic,retain) id<B_ViewDelegate> touchDelegate; //委托人指针
@end

B_View.m:  
@synthesize touchDelegate;  
- (id)initWithFrame:(CGRect)frame {  
         if (self = [super initWithFrame:frame]) {  
         [touchDelegate  touch];//调用协议委托,委托给A_View来实现函数
    }  
    return self;  
}  
@end

 

类目Category

封装是面向对象的一个特征,oc也不例外,但是有的时候我们会碰到一种情况,比如我们封装了一个类,不想再动它了,但是我们又需要在那个类中增加一个方法,这时候我们就不必在那个类中做修改或者再定义一个它的子类,只需要添加一个类目(Category)即可。建立oc的runtime机制下的,Java,C++都是有runtime机制的语言。——runtime机制简单来说就是在编译时不确定对象类型,在运行时才确定。Category提供了一种比继承(inheritance)更为简洁的方法来对class进行扩展,无需创建对象类的子类就能为现有的类添加新方法,可以为任何已经存在的class添加方法,包括那些没有源代码的类(如某些框架类)

类别主要有3个作用:
(1)可以将类的实现分散到多个不同文件或多个不同框架中,方便代码管理。也可以对框架提供类的扩展。
(2)创建对私有方法的前向引用:如果其他类中的方法未实现,在你访问其他类的私有方法时编译器报错这时使用类别,在类别中声明这些方法(不必提供方法实现),编译器就不会再产生警告
(3)向对象添加非正式协议:创建一个NSObject的类别称为“创建一个非正式协议”,因为可以作为任何类的委托对象使用。

例如:给NSString添加一个NewFunc方法,功能特点为MyCompare作为描述类目用途的唯一名字,体现按类别分开实现的思想。

类目名 NSString+MyCompare.h

#import <Foundation/Foundation.h>

@interface NSString (MyCompare)

-(void)test;

@end

类目名 NSString+MyCompare.m

#import "NSString+MyCompare.h"

@implementation NSString (MyCompare)

-(void)NewFunc{
    
}
@end

例如:AsyncSocket这个iOS Socket插件中的.h文件就是采用类目的方式想NSObject添加了相关的Socket功能,减少了插件采用协议方式造成的开发麻烦。

@interface NSObject (AsyncUdpSocketDelegate)

- (void)onUdpSocket:(AsyncUdpSocket *)sock didSendDataWithTag:(long)tag;

- (void)onUdpSocket:(AsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error;

- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port;

- (void)onUdpSocket:(AsyncUdpSocket *)sock didNotReceiveDataWithTag:(long)tag dueToError:(NSError *)error;

- (void)onUdpSocketDidClose:(AsyncUdpSocket *)sock;

@end

 

 

 

iOS视图控制

一、UIWindow是一种特殊的UIView,通常在一个程序中只会有一个UIWindow,但可以手动创建多个UIWindow,同时加到程序里面。UIWindow在程序中主要起到三个作用:

  1、作为容器,包含app所要显示的所有视图

  2、传递触摸消息到程序中view和其他对象

  3、与UIViewController协同工作,方便完成设备方向旋转的支持

二、通常我们可以采取两种方法将view添加到UIWindow中:

  1、addSubview

  直接将view通过addSubview方式添加到window中,程序负责维护view的生命周期以及刷新,但是并不会为去理会view对应的ViewController,因此采用这种方法将view添加到window以后,我们还要保持view对应的ViewController的有效性,不能过早释放。

  2、rootViewController

  rootViewController时UIWindow的一个遍历方法,通过设置该属性为要添加view对应的ViewController,UIWindow将会自动将其view添加到当前window中,同时负责ViewController和view的生命周期的维护,防止其过早释放

三、WindowLevel

  UIWindow在显示的时候会根据UIWindowLevel进行排序的,即Level高的将排在所有Level比他低的层级的前面。级别的高低顺序从小到大为Normal < StatusBar < Alert,这说明当Level层级相同的时候,只有第一个设置为KeyWindow的显示出来,后面同级的再设置KeyWindow也不会显示。(keyWindow是指定的用来接收键盘以及非触摸类的消息,而且程序中每一个时刻只能有一个window是keyWindow)

 

四、UIViewControl 管理程序中的众多视图

view最好在需要显示时再去加载,并且在系统发出内存警告时释放必要的view及相关的数据对象。

1、初始化时会根据需要调用init,initWithCoder等相关函数,这个时候我们可以做一下简单的初始化操作,建立ViewController中需要使用的数据模型等

不建议在初始化阶段就直接创建view及其他与显示有关的对象(应该放到loadView的时候去创建,或者采用懒加载的方法创建)ViewController可以通过代码和xib两种方式创建,这两种方式的初始化流程也不尽相同。

  1)使用xib创建的VC

  xib其实最终是会把我们的设置保存成一个数据集,当需要初始化构建VC的时候,回去读取记录的数据集,然后帮我们动态的创建VC,因此可以想象它在初始化时会先去找看是否实现initWithCoder方法,如果该类实现了该方法,就直接调用initWithCoder方法创建对象,如果没有实现的话就调用init方法。调用完初始化方法以后紧接着会调用awakeFromNib方法,在这个方法里面我们可以做进一步的初始化操作。

  2)使用代码创建VC

  使用代码创建时,我们根据需要手动的创建VC中的数据,如果自己定制VC时,还需要在init中调用[super init]。

2、UIViewController中View的load和unload生命周期

  前面讲了不建议在VC初始化的时候就创建view及其他与显示相关的代码,官方文档建议将View的初始化操作放到loadView的时候再做,当VC接到内存告警时会调用didRecieveMemoryWarning这个时候我们就要做出响应,释放暂时不需要的对象。如果无视这个警告,系统内存不够用时会会继续发送,如果还得不到处理就会强制退出程序。下面看具体的loadView和unloadView时候都会做什么操作。

  1)Load周期

  当需要显示或者访问view属性时,view没有创建的话,VC就会调用loadView方法,在这个时候会创建一个view并将其赋给VC.view属性。紧接着就会调用VC的viewDidLoad方法,这个时候VC.view保证是有值的,可以做进一步的初始化操作,例如添加一些subview。注意:定制VC时,如果覆盖loadView方法,不需要调用[super loadView]方法。

  2)Unload周期

  当app收到内存警告的时候,会调用每一个VC的didRecieveMemoryWarning方法,我们需要做出响应,释放程序中暂时不需要的资源。通常都会重写该方法,重写时候需要调用super的该方法。如果检测到当前VC的view可以被安全释放的话,就会调用viewWillUnload方法,当VC的view消失时候它的subviews可能会被一起释放。调用viewWillUnload以后,会将VC.view属性设置成nil,然后在调用viewDidUnload方法,这个时候我们可以释放那些强引用的对象。

 

iOS开发入门知识点总结,,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。