Objective-C初探
Objective-C简介(简称OC)
基于C语言,增加了最小的面向对象语法,完全兼容C语言
MacOSX和iOS平台的开发语言
可以购入C、C++代码
OC语法纵览1
OC中没有类似Java中的包名这个概念,取而代之的是程序设计师必须给类名加上前缀,使用前缀可以有效的防止名称冲突。
如NSString、NSArray(前缀都是NS)
为了避免跟C、C++的关键字冲突,所有的OC关键字以@开始,比如
@interface,@implementation,@end
@public,@protected,@private,@selector
@try,@catch,@throw,@finally
@protocl,@class
OC2.0中引入的新关键字有
@property,@synthesize
@optional,@required,@dynamic
OC语法纵览2
基本数据类型int、float、double、char、Bool(YES/NO)等
id类型每个对象都可以表达为id类型,可以认为是NSObject*或者void*
nil等同于NULL
基本语法循环语句(dowhile、while、for)、条件语句(if、ifelse、switch)、Boolean(YESNO)、条件运算符、goto语句、空语句、逗号表达式、sizeof运算符、命令行参数、位操作都和C一样
for循环扩展for(xxinxx)
基类NSObject
继承单继承
多态支持多态
抽象类支持抽象类
异常处理@try@catch@finally
日志输出NSLog(@"HelloWorld");NSLog(@"Myageis%i",25);
注释/*......*/和//
OC语法纵览3
OC提供了BOOL类型,但是这个Bool类型和C++里的并不一样;在C++里一切非0值的东西都为true,而为0值为false,但在OC里1为true并被宏定义为YES,0为false并被宏定义为NO
所以,下面的代码,肯定是错误的:
BoolareDifferent(inta,intb)
{
return(a-b);
}
if(areDifferent(23,5)==YES)
{}
因为areDifferent返回的是两个整数的差,如果这个差不为1,那么永远不会YES
类的定义
OC中类分为2个文件
.h,类的声名文件,用于声名变量、函数(方法)
.m,类的实现文件,用于实现.h中的函数(方法)
类的声名使用关键字@interface、@end
类的实现使用关键字@implemantation、@end
方法的声名和实现,都必须以+或者-开头
+表示类方法(静态方法)
-表示对象方法(动态方法)
在.h中声明的所有方法都public类型(通过Category可以实现private)
变量的作用域
@public全局都可以访问
@protected只能在类内部和子类中访问
@private只能在类内部访问
变量必须定义在类的{}中
类的声明-Student
#import <Foundation/Foundation.h> @interface CLStudent : NSObject { int age; int no; } -(int) age; //int getAge() -(void)setAge:(int) _age; //getAget(int age); -(int)no; -(void)setNo:(int) _no; -(void)setAgeAndNo:(int) _age:(int)_no; -(void) Age:(int) _age No:(int) _no; @end #import "CLStudent.h" //系统引用框架要用坚括号 @implementation CLStudent - (int)age{ return age; } -(void)setAge:(int)_age{ age = _age; } - (int)no{ return no; } - (void)setNo:(int)_no{ no = _no; } -(void)setAgeAndNo:(int)_age :(int)_no{ no = _no; age = _age; } -(void) Age:(int)_age No:(int)_no{ age = _age; no = _no; } @end #import <Foundation/Foundation.h> #import "CLStudent.h" int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World! %i",10); printf("Hello, World!"); //分配内存空间 CLStudent *temp = [CLStudent alloc]; //调用构造函数进行初始化 CLStudent *stu = [temp init]; [stu release]; CLStudent *student = [[CLStudent alloc] init]; [student setAge:10]; [student setNo:15]; NSLog(@"age is %i,no is %i",[student age],[student no]); [student setAgeAndNo:20 :25]; NSLog(@"age is %i,no is %i",[student age],[student no]); [student Age:21 No:26]; NSLog(@"age is %i,no is %i",[student age],[student no]); [student release]; } return 0; }
框架
所谓框架,就是一个集合,其中包含着头文件等资源文件
每个框架中均有一个主头文件,该头文件包含了框架中各个头文件,一但引入了主头文件,就可以在自己的程序里使用任何框架里类
比如要使用Foundation框架,就导入它的主头文件即可:
#import<Foundation/Foundation.h>
Cocoa简介
NextStep是一个用Objective-C编写的功能强大的工具包,里面有大量的类库,结构体等,被苹果收购后,更名为Cocoa,但苹果公司并未更改NextStep中的类库名称,因此会有大量以NS为前缀的类名、结构体、枚举等
Cocoa里面的任何类都要继承自NSObject(只有这样,该类的对象才可以获得运行时的基本能力)
Cocoa包含两个核心框架:Foundtion框架和Appkit框架,用于开发MacOSX平台的应用程序
Cocoa框架在iOS上叫做CocoaTouch,包含两个核心框架:Foundation框架和UIKit框架,用于开发iOS平台的应用程序(iPhone\iPod\iPad)
CocoaTouch与Cocoa一个比较鲜明的区别就是CocoaTouch并不支持垃圾回收机制,这就意味着你必须在你的代码里管理好你的内存
常用拓展名
拓展名含义
.h头文件。用于描述类的组件,包含成员变量、成员方法、类变量、类方法
.cc源文件
.cpp.ccc源文件
.mobjective-c源文件,也叫实现类的类文件,可以包含Objective-C和C代码,一般一个.m文件会和一个.h相对应。
.mmobjective-c++源文件,除了Objective-C和C代码,还可以包含C++代码
#import
C/C++中使用#include导入头文件,缺点就是同一个头文件可能被导入多次
C/C++为了防止多次导入同一个头文件
#ifndef_TEST_H_
#define_TEST_H_
#include"test.h"
#endif
OC中使用#import导入头文件,优点是可以自动防止同一个头文件被导入多次
创建/销毁对象
分配内存空间,创建对象
Student*stu=[Studentalloc];
调用构造方法,初始化对象
[stuinit];
销毁对象
[sturelease];
一般来说创建和初始化连着一起操作
Student*stu=[[Studentalloc]init];
/*...........................*/
[sturelease];
构造方法
-(CLStudent *)initWwithAge:(int) newAge; -(CLStudent *)initWwithAge:(int)newAge{ if(self = [super init]){ age = newAge; return self; } return nil; } CLStudent *students = [[CLStudent alloc] initWwithAge:23]; NSLog(@"age is %i,no is %i",[students age]); [students release]; -(id)initwithAge:(int) newAge andNo:(int)newNo; -(id)initwithAge:(int)newAge andNo:(int)newNo{ if(self = [self initWwithAge:newAge]){ no = newNo; return self; } return nil; } CLStudent *student2 = [[CLStudent alloc] initwithAge:24 andNo:26]; NSLog(@"age is %i,no is %i",[student2 age],[student2 no]); NSObject *obj = [[CLStudent alloc] init]; id obj1 = [[CLStudent alloc] init]; [student2 release];
实例化二
NSObject*obj=[[CLStudentalloc]init];
NSObject*obj=[CLStudentnew];
注释
#pragmamark-getter注释一类方法
#pragmamark设置年龄单个方法注释
也可以安装额外的服务生成Doxygen文档注释
点语法(调用是set/get方法)
student2.age=10;
NSLog(@"ageis%i,nois%i",student2.age,student2.no);
@property作用
@propertyintage;自动声明set/get方法
-(int)age;//intgetAge()
-(void)setAge:(int)_age;//getAget(intage);
@property(readwrite,getter=getID)intage;
@property(readwrite,atomic,retain)intage;
@synthesize作用
@synthesizeage;自动生成实现set/get方法
内存管理
范围
任何继承了NSObject的对象,对基本数据类型无效
原理
每个对象内部都保存了一个与之相关的整数,称为引用计数器
当使用alloc、new或者copy创建一个对象时,对象的引用计数器被设置为1
给对象发送一条retain消息,可以使引用计数器值+1
给对象发送一条releain消息,可以使引用计数器值-1
当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收,OC也会自动向对象发送一条dealloc消息,一销毁会重写dealloc方法,在这里释放相关资源,一定不要直接调用dealloc方法
可以给对象发送retainCount消息获得当前的引用计数器值
@class
在申明时使用@class
在使用时使用#import
assign直接赋值
自动释放池(autoreleasepool)
自动释放池OC里面的一种内存回收机制,一般可以将一些临时变量添加到自动释放池中,统一回收释放
当自动释放池销毁时,池里面所有对象都会调用一次release方法
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; Student *student = [[[Student alloc] init] autorelease]; NSLog(@"%@",student); //[student description]==toString(); [student hash] ==hashcode [pool release];
Catgory
OC提供一种与众不同的方式-Catagory,可以动态的为已经存在的类添加新的行为(方法)
这样可以保证类的原始设计规模较小,功能增加时再逐步扩展
使用Category对类进行扩展时,不需要访问其源代码,也不需要创建子类
Category使用简单的方式,实现子类的相关方法的模块化,把不同的类方法分配到不同的分类文件中
Category的使用注意
Category可以访问原始类的实例变量,但不能添加变量,如果想添加变量,可以考虑通过继承创建子类
Category可以重载原始类的方法,但不推荐这么做,因为它是直接替换掉原来的方法,这么做的后果是再也不能访问原来的方法,如果确定要重载,正确的选择是创建子类
在分类的实现文件中可以不必实现所有声明的方法,只要你不去调用它
类的私有方法
第一种方式:直接在.m文件中写方法,不要在.h文件中进行方法声明,不然又是公共方法了
第二种方式:在.m文件中定义一个Category(分类),在Category中声明一些方法,然后在@implementation跟@end之间作方法实现
Protocol
简单来说就是一系列不属于任何类的方法列表,其中声明的方法可以被任何类实现,这促模式一般称为代理(delegation)模式
在iOS和OSX开发中,Apple采用了大量的代理模式来实现MVC中View(UI控件)和Controller(控制器)的解耦
#import <Foundation/Foundation.h> @protocol MyBtnDelege <NSObject> //实现 NSObject @required //必须实现方法 @optional可选 -(void)btnClick:(id)sender; @end #import <Foundation/Foundation.h> @protocol MyBtnDelege; @interface MyBtn : NSObject //监听器 @property (retain,nonatomic) id<MyBtnDelege> delegate; -(void)click; @end
#import "MyBtn.h" #import "MyBtnDelege.h" @implementation MyBtn @synthesize delegate = _delegate; -(void)click{ //通知监听器 if(_delegate != nil){ Bool b = [_delegate conformsToProtocol:@protocol(MyBtnDelege)]; //判断协议是否是当前协议 if(b){ if([_delegate respondsToSelector:@selector(btnInit:)]){ //判断是否实现方法 [_delegate btnClick:self]; } }else{ NSLog(@"delegate 没有实现相应的协议"); } } } -(void)dealloc{ [super dealloc]; [_delegate release]; } @end
#import "MyController.h" #import "MyBtnDelege.h" @implementation MyController -(void) btnClick:sender{ NSLog(@"按钮%被点击了"); } @end
#import <Foundation/Foundation.h> #import "MyBtn.h" #import "MyController.h" int main(int argc, const char * argv[]) { @autoreleasepool { MyBtn *btn = [[[MyBtn alloc] init] autorelease]; btn.delegate = [[[MyController alloc] init] autorelease]; [btn click]; } return 0; }
Foundation框架
NSRange
在Foundation/NSRange.h中对NSRange的定义
typedefstruct_NSRange{
NSUIntegerlocation;
NSUIntegerlength;
}NSRange;
//typedefunsignedlongNSRange;
这个结构体用来表示事物的一个范围,通常是字符串里的字符范围或者集合里的元素范围
location表示该范围的其实位置
length表示该范围内所含元素个数
比如"Iloveobjective-c"中的"obj"可以用location为7,length为3的范围来表示
NSRange
有3种方式创建一个NSRange变量
第1种:直接给成员赋值
NSRangerange;
range.location=7;
range.length=3;
第2种:应用C语言的聚合结构赋值机制
NSRangerange=(7,3);
或者NSRangerange={.location=7,.length=3);
第3种:Foundation框架提供的一个快捷函数NSMakeRange
NSRagerange=NSMakeRange(7,3);
NSRangerange={.location=1,.length=3};
NSRangerange=NSMakeRange(3,4);
NSLog(@"location:%zi,length:%zi",range.location,range.length);
NSPoint
在Foundation/NSGeometry.h中对NSPoint的定义
typedefCGPoint/CGGeometry.h中对CGpoint的相关定义
structCGPoint{
CGFloatx;
CGFloaty;
}
typedefstructCGPointCGPoint
//#defineCGFLOAT_TYPEdouble
//typedefCGFLOAT_TYPECGFloat;
NSPoint和CGPoint是等价的
这个结构体代表的平面中的一个点(x,y)
CGPointpoint=NSMakePoint(10,20);//==NSPointpoint=NSMakePoint(10,20);
NSLog(@"x:%.0f,y:%.0f",point.x,point.y);//.表示小数个数
//等价CGPointMake(10,20);
NSSize
在Foundation/NSGeometry.h中对NSSizer的定义
typedefCGSizeNSSize;
在CoreGraphics/CGGeometry.h中对CGSize的相关定义
structCGSize{
CGFloatwidth;
CGFloatheight;
};
typedefstructCGSize;
这个结构体用来存储宽度和高度
可以利用NSMakeSize()和CGSizeMake()创建CGSize
NSRect
在foundation/NSGeometry.h中对NSRect的定义
typedefCGRectNSRect;
在CoreGraphics/CGGeometry.h中对CGRect的相关定义
structCGRect{
CGPointorigin;
CGSizesize;
}
typedefstructCGRectCGRect;
这个结构体用来存储宽度和高度
可以利用NSMakeRect()和CGRectMake()创建CGRect
NSString的创建
创建常量字符
NSString*string=@"ThisisaString!";
创建空字符串,给予赋值
NSString*string=[[NSStringalloc]init];
string=@"ThisisaString";
通过字符串创建字符
[[NSStringalloc]initWithString:@"ThisisaString!"];
//或者 [[NSStringalloc]initWithFormat:@"Myageis%i",20];
NSString*string=[NSStringstringWithFormat:@"Myageis%i",20];
用标准C创建字符
char*cString="这是一串中文";
[[NSStringalloc]initWithCString:cStringancoding:NSUTF8StringEncoding];
或者 [[NSStringalloc]initWithUTF8String:cString];
//字符串编码可以在NSString.h中查阅
从文件中读取
NSString*path=@"/Users/apple/Desktop/test.txt";
NSStringEncodingenc=CFStringConvertEncodeingToNSStringEncoding(KCFStringEncodingGB_18030_2000);
NSError*error=nil;
NSString*string[[NSStringalloc]initWithContentsOfFile:pathencoding:encerror:&error];//&error指针地址--指向指针的指针
if(error!=nil){
NSLog(@"\n读取错误,错误信息:\n%@",[errorlocalizedDescription]);
}
[stringrelease];
从远程文件读取
NSError*error=nil;
NSURL*url=[NSURLURLWithString:@"http://www.baidu.com"];//NSURL*url=[NSURLURLWithString:@"file:///Users/apple/Desktop/test.txt"];
NSString*string=[[NSStringalloc]initWithContentsOfURL:url,encoding:NSUTF8StringEncoding,error:&error];
NSString文件导出
NSString*string=@"123456";
NSString*path=@"/Users/apple/Desktop/123.txt";
[stringwriteToFile:pathatomically:YESencoding:NSUTF8StringEncodingerror:nil];
[stringwriteToURL:...]//写到远程
NSString的比较
-(Bool)isEqualToString:(NSString*)string
比较两个字符串的内容是否相同,相同就返回YES,不同则返回NO
-(NSComparisonResult)compare:(NSString*)string
逐个字符地进行比较,返回NSComparisonResult来显示比较结果。
NSComparisonResult是一个枚举,有3个值
-(NSComparisonResult)caseInsensitiveCompare:(NSString*)string突略大小写比较
-(NSComparisonResult)compare:(NSString*)string options:(NSString*)string比较字符个数,而不字符
-(NSString*)uppercaseStringstring全部转为大写
-(NSString*)lowercaseStringstring全部转为小写
-(NSString*)capitalizeStringstring首字母变大写,其它字母都小写
NSString的搜索
-(BooL)hasPrefix:(NSString*)string是否以string开头
-(BooL)hassuffix:(NSString*)string是否以string结尾
-(NSRange)rangeOfString:(NSString*)string检查是否包含了atring,如果包含,返回string位置,如果不包含的location为-1,length为0
-(NSRange)rangeOfString:(NSString*)stringoptions:(NSStringCompareOptions)mask可以传递一个mask参数,改变搜索方式
比如NSStringCompareOptions为NSBackwardsSearch表示从尾部开始搜索
-(NSRange)rangeOfString:(NSString*)stringoptions:(NSStringCompareOptions)maskrange:(NSRange)searchRange还可以用searchRange指定搜索范围
NSString的截取
-(NSString*)substringFromIndex:(NSUInteger)from从指定位置from开始(包括指定位置的字符)到尾部
-(NSString*)substringToIndex:(NSUInteger)to从字符串的开头一直截取到指定位置to,但不包括该位置的字符
-(NSString*)substringWithRange:(NSRange)range按照所给出的NSRange从字符串中截取串
-(NSArray*)componentsSeparatedByString:(NSString*)separator用separator为分隔符截取子串,返回一个装着所有子串的集合NSArray
NSString与路径
-(NSString*)pathWithComponents:(NSArray*)components将components中的字符串比较按顺序拼成一个路径
-(NSArray*)pathComponents将路径分解成一个装着每一个目录的NSArray
-(BooL)isAbsolutePath是否为绝对路径
-(NSString*)lastPathComponent获取最后一个目录
-(NSString*)stringByDeletingLastPathComponent删除最后一个目录
-(NSString*)stringByAppendingPathComponent:(NSString*)str在路径的后面拼接一个目录
NSString与拓展名
-(NSString*)pathExtension获取拓展名
-(NSString*)stringByDeletingPathExtension删除尾部的拓展名
-(NSString*)strigByAppendingPathExtension在尾部添加一个拓展名
NSString其他用法
-(NSUInteger)length返回字符串的长度
-(unichar)characterAtIndex(NSUInteger)index返回index位置对应的字符
-(double)doubleValue
-(float)floatValue
-(int)intValue
-(char*)UTF8String转换C语言中的字符串
constchar*cs=[stringUTF8String];
NSMutableString
NSString是不可变的,不能删除字符或者添加字符,NSString有一个子类NSMutableString,称为”可变字符串”
创建可变字符串的常用方法
-(id)initWithCapacity:(NSUInteger)capacity
+(id)stringWithCapacity:(NSUInteger)capacity
capacity只是一个最优值,字符串的大小并不仅限于所提供的容量,设置了capacity,可以预分配一块内存来存储它,操作速度快很多
当然,也可以使用创建NSString的方法来创建NSMutableString,因为NSMutableString是NSString的子类,NSMutableString都能使用
NSMutableString*string=[NSMutableStringstringWithFormat:@"ageis%i.",20];
-(void)setString:(NSString*)string初始化完毕后可以使用此方法设置字符串的内容
-(void)appendString:(NSString*)string
-(void)appendFormat:(NSString*)format,...
这两个方法都是在尾部拼接一段字符串
-(void)replaceCharactersInRange:(NSRange)rangeWithString:(NString*)string
将range位置的字符串替换为string
-(void)insertString:(NSString*)stringatIndex:(NSUInteger)loc
在loc这个位置插入string(string的起始位置是loc)
-(void)deleteCharaCharactersInRange:(NSRange)range
删除range这个范围的字符串(经常跟rangeOfString:一起使用删除特定的字符串)
NSArray
用来存储对象的有序列表,它是不是可变的
不能存储C语言中的基本类型,如int、float、enum、struct,也不能存储nil
创建NSArray的常用方法
NSArray*array=[NSArrayarrayWithObjects:...,nil];
NSArray排序
NSArray*sort=[arraysortedArrayUsingSelector:@selector(compere:)];
NSMutableArray
可变数组
NSDictionary
通过唯一的key找到对应的value
NSNumber
NSNumber可以将基本类型包装成对象,这样就可以间接将基本数据类型存进NSArray、NSDictionary等集合中
NSValue
NSMuber是NSValue的子类,但NSNumber只能包装数字类型,NSValue可以包装任意值,也就是可以用NSValue包装结构后加入NSArray、NSDictionary等集合中
NSNull
集合中是不能存放nil值的,因为nil在集合中有特殊含义,但有时确实需要存储一个表示“什么都没有”的值,那么就以使用NSNull,它也是NSObject的一个子类
NSDate的静态初奴化
时间处理
反射
NSString*dogName=@"Dog";
Classclass=NSClassFromString(dogName);
Dog*dog=[[[classalloc]init]autorelease];
NSString*methodName=@"print";
SELmethod=NSSelectorFromString(methodName);
[dogperformSelector:method];
@property(nonatomic,retain)NSString*aString;
property:属性的定义,相当于C语言的setter和getter方法。
assign:简单的赋值,不更改索引的计数。
copy:建议一个索引计数为1的对象,然后释放旧对象;
retain:释放旧对象,将旧对象的值赋予新对象,再增加新对象的索引计数1。
针对具体的数据类型在属性定义应该这样选择:
使用assign:对基础的数据类型,比如NSInterger,CGFloat和C数据类型(int,float,double,char等等)。
使用copy:针对NSString;
使用retain:针对NSObject及其子类。
使用nonatomic:单线程,防止在写未完成的时候被另外一个线程读取,造成数据读取出错。
使用release:基于一般的初始化,使用alloc和init关键词初始化的,要在恰当的地方release掉,全局变量在dealloc方法里面release,常规变量在不需要的时候就要释放掉。
ios关闭键盘的两种方法
[[[UIApplicationsharedApplication]keyWindow]andEditing:YES];
递归找到“叫出”键盘的控件,让它把键盘给退回去