oc和c的差别
- OC中用#import导包
- OC不考虑重复包含
- OC头文件用.h结束
- 完全兼容c语言 语法和函数
object-c基础语法
第一讲:OC简介及基本语法
Objective-C简称OC是在C语言的基础上,增加了一层最小的面向对象语法,完全兼容C语言,也就是可以在OC代码中混入C语言代码,甚至是C++代码。可以使用OC开发Mac OS X平台和IOS平台的应用程序。简单的介绍了一下OC,下面我们来看看OC的基本语法,学习OC之前我们先学习了C语言,因为OC是在C语言的基础上的一门开发语言,因此OC的很多基本语法跟使用方法跟C语言有类似的地方但是也有其独特的地方。
1. 关键字
OC中的关键字基本上所有的都是以@开头,但也有少数不是以@开头的,下面是一些较常用的关键字:
@interface、@implementation、@end @public、@protected、@private、@selector @try、@catch、@throw、@finally @protocol、@optional、@required、@class @property、@synthesize、@dynamic self、super、id、_cmd、__block、__strong、__weak、
2. 字符串以@开头
比如@"Hello"是OC中的字符串,而"Hello"则是C语言中的字符串
3. OC程序的开发过程
OC程序的开发跟C语言类似,从 .m源文件编译成 .o目标文件再链接成 a.out可执行文件
4. 程序框架
OC程序的入口也是main函数
在编写第一个OC程序时用到了OC的输出函数NSLog,但调用NSLog需要包含Foundation框架,OC中一般使用#import <Foundation/Foundation.h>来包含Foundation框架,每个框架都有自己的主头文件:即最主要的头文件。主头文件名字一般跟框架名称一样,包含了框架中的所有其他头文件,Foundation框架的主头文件名称就是Foundation.h,只需要包含Foundation框架的主头文件,就可以使用整个框架的东西。
其中#import的作用:跟C语言中#include一样,用来拷贝某个文件的内容,#import可以自动防止文件内容被拷贝多次,也就意味着头文件中不用加入相应的预处理指令。
#import <Foundation/Foundation.h>
//OC程序的入口:main函数
int main()
{
//printf("第一个OC程序\n");//OC完全兼容C语言程序
NSLog(@"第一个OC程序"); //NSLog输出内容会自动换行
return 0;
}
5. NSLog与printf的区别
NSLog接收OC字符串作为参数,printf接收C语言字符串作为参数
NSLog输出后会自动换行,printf输出后不会自动换行
使用NSLog需要
#import <Foundation/Foundation.h>
使用printf需要
#include <stdio.h>
6. Foundation框架的作用
开发OC、iOS、Mac程序必备的框架
此框架中包含了很多常用的API(应用编程接口)
框架中包含了很多头文件,若想使用整个框架的内容,包含它的主头文件即可:
#import <Foundation/Foundation.h>
7. BOOL的使用
BOOL类型的本质 typedef signed char BOOL;
BOOL类型的变量有2种取值:YES、NO
#define YES (BOOL)1
#define NO (BOOL)0
BOOL的输出(当做整数来用)
NSLog(@"%d %d", YES, NO);
第二讲:类和对象
OC是一门面向对象的开发语言,而C语言是面向过程的,因此在开发思想上要把面向过程和面向对象好好区分开来,体会其中的不同之处。面向过程关注的是解决问题需要哪些步骤,而面向对象关注的是解决问题需要哪些对象。
1. 类的设计
在C语言中完整的写一个函数需要函数的声明和定义(也就是实现),而OC中类似,完整的写一个类需要类的声明和实现
类的设计主要包括:类名,属性和行为
设计类名注意点:
- 类名的第一个字母必须是大写
- 不能有下划线
- 多个英文单词,用驼峰标识
2. 方法(行为)的设计
OC中方法就是行为,主要包括方法名,参数,返回值(声明和实现)方法不能放在大括号里面
注意点:
- 只要是OC对象的方法,必须以减号 - 开头,类方法以+开头
- OC方法中任何数据类型都必须要用()扩住
- OC方法中的小括号():只有一个作用,用来扩住数据类型
3. 类的声明和实现
OC中类的声明值得是用来声明对象的属性跟行为,声明对象的属性(实例变量或者叫成员变量) , 成员变量默认情况下会做一个初始化,所有成员变量默认都是0
声明在@interface和@end之间进行,实现在@implementation和@end之间进行
在使用类创建对象之前,会将类加载进内存,类的内存里面只放方法列表,创建的每个对象内部默认有一个指针(isa指针),这个指针指向这个对象所对应的类,所有的对象共用相同的类里面的方法。
类的声明跟实现常见错误:
-
只有类的声明,没有类的实现
-
漏了@end ,@interface和@implementation嵌套
-
两个类的声明嵌套
-
成员变量没有写在括号里面
-
方法的声明写在了大括号里面
语法细节:
-
成员变量不能在{}中进行初始化、不能被直接拿出去访问
-
方法不能当做函数一样调用
-
成员变量\方法不能用static等关键字修饰,别跟C语言混在一起(暂时忽略)
-
类的实现可用写在main函数的后面,主要在声明后面就行了
4. 方法跟函数的区别
方法:
-
对象方法都是以减号-开头
-
对象方法的声明必须写在@interface和@end之间
-
对象方法的实现必须写在@implementation和@end之间
-
对象方法只能由对象来调用
-
对象方法归类\对象所有
函数:
-
函数能写在文件中的任意位置(@interface和@end之间除外),函数归文件所有,函数可以定义在@implementation和@end之间,这个是没有问题完全可以
-
函数调用不依赖于对象
-
函数内部不能直接通过成员变量名访问某个对象的成员变量
5. 方法的声明和实现
@interface JiSuanQi : NSObject
- (double)pi; // 方法名叫pi,不带参数的方法
// OC方法中,一个参数对应一个冒号
// 方法名叫pingFang: ,要连上冒号,为了防止方法名的冲突,冒号也是方法名的一部分
- (int)pingFang:(int)num; // 带一个参数的方法
// 方法名叫: sumWithNum1:andNum2:
- (int)sumWithNum1:(int)num1 andNum2:(int)num2; // 带两个参数的方法,可读性好 冒号前面加一些描述信息,来描述后面的参数是干嘛用的
@end
因此注意在定义方法名时要注意一些规范,保证可读性好,类似于 sumWithNum1:andNum2:这种的方法名。
第三讲:三大特性
第三讲我们主要讲OC的三大特性,OC是一门面向对象的语言,面向对象的开发语言一般共同的特点就是具有三大特性:封装,继承和多态。下面我们来学习一下OC的三大特性。
一、 封装
封装就是对类中的一些字段,方法进行保护,不被外界所访问到,有一种权限的控制功能。
封装的好处:过滤不合理的值,屏蔽内部的赋值过程,让外界不必关注内部的细节。
1. set方法和get方法
set方法
作用:提供一个方法给外界设置成员变量值,可以在方法里面对参数进行相应过滤
命名规范:
(1)方法名必须以set开头
(2)set后面跟上成员变量的名称,成员变量的首字母必须大写
(3)返回值一定是void
(4)一定要接收一个参数,而且参数类型跟成员变量类型一致
(5)形参的名称不能跟成员变量名一样
get方法
作用:返回对象内部的成员变量
命名规范:
(1)肯定有返回值,返回值类型肯定与成员变量类型一致
(2)方法名跟成员变量名一样
(3)不需要接收任何参数
2. 成员变量的命名规范:一定要以下划线 “_” 开头
作用:
让成员变量和get方法的名称区分开
可以跟局部变量区分开,一看到下划线开头的变量,一般都是成员变量
3. 经典错误
#import <Foundation/Foundation.h>
@interface Person : NSObject
@end
@implementation Person
@end
int main()
{
Person *p = [Person new];
// OC是在运行过程中才会检测对象有没有实现相应的方法
[p test];//实现中没有test方法
return 0;
}
报错:-[Person test]: unrecognized selector sent to instance 0x7fd2ea4097c0
给Person对象发送了一个不能识别的消息:test
4. 类方法和对象方法
(1)对象方法:
*减号 - 开头
*只能由对象来调用
*对象方法中能访问当前对象的成员变量(实例变量)
(2)类方法:
*加号 + 开头
*只能由类(名)来调用
*类方法中不能访问成员变量(实例变量)
(3)类方法的好处和使用场合:
*不依赖于对象,执行效率高
*能用类方法尽量用类方法
*场合:当方法内部不需要使用到成员变量时,就可以改为类方法
*可以允许类方法和对象方法同名
5. self关键字
self关键字是个指针,self指向方法调用者,代表着当前对象,当成员变量和局部变量同名时,采取就近原则,访问的是局部变量,用self访问成员变量,区分同名的局部变量
self用途:
(1)谁调用了当前方法,self就代表谁,(指向了当前对象-方法调用者)
* self出现在对象方法中,self就代表对象
* self出现在类方法中,self就代表类
(2)在对象方法中利用“self->成员变量名”访问当前对象内部的成员变量
(3)[self 方法名] 调用当前对象的某一个方法,可以调用其他对象方法或者类方法
常见错误:
*低级错误:用self去调用函数
*类方法中用self调用对象方法,对象方法中用self调用类方法
*self死循环
二、 继承
继承是类中的一个重要的特性,他的出现使得我们没必要别写重复的代码,可重用性很高。继承的一些专业术语:父类\超类:superclass 子类:subclass\subclasses
1.继承的好处:
*抽取重复代码
*建立了类之间的关系
*子类拥有父类中的所有成员变量和方法
*注意点:基本上所有类的根类是NSObject
2. 方法的重写
重写:子类重新实现父类中的某个方法,覆盖父类以前的做法
注意:
*父类必须声明在子类的前面,实现可以放在子类的后面
*子类不能拥有和父类相同的成员变量
*调用某个方法时,优先去当前类中找,如果找不到,去父类中找
*坏处:耦合性太强:类之间的关系太紧密了,当某个父类不见了,子类就用不了
3. 继承的使用场合
当两个类拥有相同属性和方法的时候,就可以将相同的东西抽取到一个父类中
当A类完全拥有B类中的部分属性和方法时,可以考虑让B类继承A类
4. 继承和组合
当某个类想拥有另一个类当中的东西,考虑两种方式,一种是继承一种是组合
继承:xx 是 xxx 代表什么什么(子类)是什么什么(父类)
组合:xxx 拥有 xxx
类A
{
int _age;
int _no;
}
类B
{
A *_a; // B里面拥有A,这个是组合
int _weight;
}
在实际的使用中,要注意逻辑和设计,区分好继承和组合的使用。
5. super关键字
super的作用和使用场合:
*直接调用父类中的某个方法
*super处在对象方法中,那么就会调用父类的对象方法
*super处在类方法中,那么就会调用父类的类方法
*使用场合:子类重写父类的方法时想保留父类的一些行为
三、 多态
多态指的是某一类事物的多种形态,OC对象具有多态性
多态的体现:Person *p = [Student new]; p->age = 10; [p walk];
1. 多态的使用注意
*没有继承就没有多态
*代码的体现:父类类型的指针指向子类对象
*好处:如果函数\方法参数中使用的是父类类型,可以传入父类,子类对象
*局限性:父类类型的变量 不能 直接调用子类特有的方法。必须强制转为子类类型的变量后,才能直接调用子类特有的方法。
2. 代码中的注意点
Animal *a = [Dog new];
//[a run];run方法为Dog独有,不能直接访问
Dog *d = (Dog *)a;//强制转换为Dog *类型才能调用run方法
[d run];
控件学习
第一课 UILabel和Button
UILabel 类似于TextView,属性基本一致。
//创建UI控件函数
- (void) createUILabel
{
//textview
UILabel* label=[[UILabel alloc] init];
//background
label.backgroundColor=[UIColor grayColor];
//text
label.text=@"先帝创业未半而中道崩殂";
//在屏幕上的位置 和 自身大小
//p1 :距x轴位置
//p2: 距Y轴位置
//p3: width
//p4: height
label.frame=CGRectMake(100,100 , 160, 80);
//textsize 文字大小
label.font=[UIFont systemFontOfSize:24];
//textcolor 文字颜色
label.textColor=[UIColor blueColor];
//阴影
label.shadowColor=[UIColor redColor];
label.shadowOffset=CGSizeMake(0, 3);
//gravity
label.textAlignment=NSTextAlignmentCenter;
//默认是1,>0文字会按照设置的行数显示,=0会自动z计算
label.numberOfLines=0;
[self.view addSubview:label];
}
button视图的实现和使用
-(void)creatUIRectButton{
//创建一个btn对象,根据类型来创建button
//圆角类型btn,UIButtonTYpeRoundedRect
//通过类方法来创建 buttonWithType:类名+方法名
UIButton* btn=[UIButton buttonWithType:UIButtonTypeRoundedRect];
//设置按钮的位置
btn.frame=CGRectMake(100, 100, 100, 40);
//设置按钮的文字内容和颜色
[btn setTitle:@"正常" forState:UIControlStateNormal];
// [btn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
//按下状态
[btn setTitle:@"按下" forState:UIControlStateHighlighted];
// [btn setTitleColor:[UIColor blueColor] forState:UIControlStateHighlighted];
//背景颜色
btn.backgroundColor=[UIColor blueColor];
//设置按钮的风格颜色,会被上面覆盖,优先级没有titlecolor高
[btn setTintColor:[UIColor whiteColor]];
//字体大小
btn.titleLabel.font=[UIFont systemFontOfSize:18];
//点击事件
//3个参数
//目标(谁来实现)、函数对象(出发动作要干什么)、什么动作触发
//UIControlEventTouchUpInside当手指离开并手指在按钮范围内
[btn addTarget:self action:@selector(pressBtn:) forControlEvents:UIControlEventTouchUpInside];
//按钮标识
btn.tag=101;
[self.view addSubview:btn];
}
Button的点击事件
-(void) pressBtn:(UIButton*) btn{
switch (btn.tag) {
case 101:
NSLog(@"press01 up");
break;
case 102:
NSLog(@"press02 up");
break;
default:
break;
}
}
图片背景的Button,方法和Android差不多
-(void) createImageBtn{
//创建一个可以显示 图片的按钮
UIButton* btnImage=[UIButton buttonWithType:UIButtonTypeCustom];
btnImage.frame=CGRectMake(100, 300, 100, 100);
UIImage* icon01=[UIImage imageNamed:@"common_password_icon"];
UIImage* icon02=[UIImage imageNamed:@"common_open_mine"];
[btnImage setImage:icon01 forState:UIControlStateNormal];
[btnImage setImage:icon02 forState:UIControlStateHighlighted];
[btnImage addTarget:self action:@selector(pressBtn:) forControlEvents:UIControlEventTouchUpInside];
btnImage.tag=102;
[self.view addSubview:btnImage];
}
第二课 UIViewControl的生命周期和UIIView
生命周期
初始化方法,只会加载一次,里面是UIView的使用
//只会加载一次
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSLog(@"视图第一次加载,并且只会加载一次");
//uiview是ios中的视图对象,显示在屏幕上的虽有对象的基础类
//他是一个矩形对象,有背景颜色,可以显示,有层级关系
UIView* view=[[UIView alloc] init];
//frame是uiview的属性
view.frame=CGRectMake(100, 200, 100,100);
view.backgroundColor=[UIColor blueColor];
//将新建的视图显示在父视图上,
//1.显示在屏幕上
//2.作为子视图管理起来
[self.view addSubview:view];
//i隐藏视图 yes
//默认是no
view.hidden=NO;
//设置透明度
//alpha=1不透明
//=0透明
//=0.5 半透明
view.alpha=1;
//设置是否显示不透明
view.opaque=NO;
//讲自己从父视图移除
// [view removeFromSuperview];
//关于uiview的层级
//先添加的先绘制
UIView* view01=[[UIView alloc] init];
view01.frame=CGRectMake(120, 240, 100,100);
view01.backgroundColor=[UIColor greenColor];
UIView* view02=[[UIView alloc] init];
view02.frame=CGRectMake(140, 260, 100,100);
view02.backgroundColor=[UIColor orangeColor];
//将新建的视图显示在父视图上,
//1.显示在屏幕上
//2.作为子视图管理起来
[self.view addSubview:view];
[self.view addSubview:view01];
[self.view addSubview:view02];
//调整视图到最前方
// [self.view bringSubviewToFront:view];
// [self.view sendSubviewToBack:view02];
self.view.backgroundColor=[UIColor whiteColor];
}
当视图即将显示时
//当视图即将显示时
//显示前-正在显示-被隐藏
//参数表示是否有动画切换
- (void)viewWillAppear:(BOOL)animated
{
NSLog(@"视图即将显示");
}
视图即将消失
//视图即将消失
//当前视图还显示在屏幕上
- (void)viewWillDisappear:(BOOL)animated{
NSLog(@"视图即将消失");
}
当视图已经显示到屏幕后的瞬间调用此函数
//当视图已经显示到屏幕后的瞬间调用此函数
//当前视图已经显示在屏幕上
- (void)viewDidAppear:(BOOL)animate
{
NSLog(@"视图已经显示");
}
当视图从屏幕上消失
//当视图从屏幕上消失
//当前视图已经从屏幕上消失
- (void)viewDidDisappear:(BOOL)animated
{
NSLog(@"视图已经消失");
}
2018-10-20 12:54:43.792602+0800 IosTest[35286:2553222] 视图第一次加载,并且只会加载一次
2018-10-20 12:54:43.792960+0800 IosTest[35286:2553222] 视图即将显示
2018-10-20 12:54:43.848378+0800 IosTest[35286:2553222] 视图已经显示
2018-10-20 12:54:45.957212+0800 IosTest[35286:2553222] 视图即将消失
2018-10-20 12:54:46.474963+0800 IosTest[35286:2553222] 视图已经消失
第三课 UISwitch、UIProgressView和UISlider
UISwitch:
//初始化
_mySwitch=[[UISwitch alloc] init];
//宽度和高度无法改变
_mySwitch.frame=CGRectMake(100, 100, 80, 40);
//设置开关状态
_mySwitch.on=YES;
[_mySwitch setOn:YES];
[_mySwitch setOn:YES animated:YES];
//开启状态的颜色
[_mySwitch setTintColor:[UIColor orangeColor]];
//开关圆点的颜色
[_mySwitch setThumbTintColor:[UIColor redColor]];
//默认的颜色
[_mySwitch setTintColor:[UIColor blueColor]];
//开关控件添加事件
[_mySwitch addTarget:self action:@selector(swtOn:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:_mySwitch];
开关事件
- (void) swtOn:(UISwitch*) swt
{
if(swt.on){
NSLog(@"开关被打开");
}else{
NSLog(@"开关被关闭");
}
}
UIProgressView
_progressView=[[UIProgressView alloc] init];
//高度不能变更
_progressView.frame=CGRectMake(50, 100, 200, 40);
_progressView.progressTintColor=[UIColor redColor];
//0-1 设置进度值
_progressView.progress=0.5;
_progressView.progressViewStyle=UIProgressViewStyleDefault;
_progressView.trackTintColor=[UIColor blueColor];
[self.view addSubview:_progressView];
UISlider 滑动条
_slider=[[UISlider alloc] init];
//高度不能变更
_slider.frame=CGRectMake(10, 200, 300, 40);
_slider.maximumValue=1;
//可以为负值
_slider.minimumValue=0;
_slider.value=0.3;
//滑块左侧的颜色
_slider.minimumTrackTintColor=[UIColor redColor];
//滑块右侧的颜色
_slider.maximumTrackTintColor=[UIColor greenColor];
//滑块的颜色
_slider.thumbTintColor=[UIColor blueColor];
[_slider addTarget:self action:@selector(slideValue:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:_slider];
滑动事件监听
-(void) slideValue:(UISlider*) slider
{
_progressView.progress=_slider.value-_slider.minimumValue/_slider.maximumValue-_slider.minimumValue;
}
第四课 NSTimer定时器
可以在每隔固定时间发送一个消息
通过此消息来调用相应的时间函数
通过此函数可在固定时间段来完成一个根据时间间隔的任务
UIButton* btn=[UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.frame=CGRectMake(100, 100, 80, 40);
[btn setTitle:@"启动定时器" forState:UIControlStateNormal];
[btn addTarget:self action:@selector(pressStart) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
UIButton* btnStop=[UIButton buttonWithType:UIButtonTypeRoundedRect];
btnStop.frame=CGRectMake(100, 150, 80, 40);
[btnStop setTitle:@"停止定时器" forState:UIControlStateNormal];
[btnStop addTarget:self action:@selector(pressStop) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btnStop];
UIView* view=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 80, 80)];
view.backgroundColor=[UIColor orangeColor];
view.tag=103;
[self.view addSubview:view];
创建并开始定时器函数
-(void) pressStart
{
//NSTimer的类方法创建一个定时器并启动这个定时器
//p1:每个多长时间调用定时器函数,以秒为单位
//p2:表示实现定时器的函数的对象
//p3:定时器函数对象
//p4:可以传入定时器里的一个参数,
//p5:定时器是否重复 YES为重复
//返回一个新建好的定时器对象
_timerView=[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(uploadTimer:) userInfo:@"小明" repeats:YES];
}
停止函数
-(void) pressStop
{
if (_timerView!=nil) {
//停止计时器
[_timerView invalidate];
}
}
定时器函数 移动view
//定时器函数
-(void) uploadTimer:(NSTimer*) timer
{
NSLog(@"test......name=%@",timer.userInfo);
UIView* view=[self.view viewWithTag:103];
view.frame=CGRectMake(view.frame.origin.x+5, view.frame.origin.y+5, 80, 80);
}
第五课 UIStepper步进器和UISegmentedControl分栏器
定义步进器
按照一定的数值来调整某个数值
UIStepper* _stepper;
分栏器
UISegmentedControl* _segControl;
_label=[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
_label.textAlignment=NSTextAlignmentCenter;
[self.view addSubview:_label];
_stepper=[[UIStepper alloc] initWithFrame:CGRectMake(100, 100, 80, 40)];
_stepper.maximumValue=100;
_stepper.minimumValue=0;
_stepper.value=10;
_label.text=[NSString stringWithFormat:@"%f",_stepper.value];
//每次步进的值
_stepper.stepValue=5;
//是否可以重复响应事件操作
_stepper.autorepeat=YES;
//是否将步进结果通过事件函数响应出来
_stepper.continuous=YES;
[_stepper addTarget:self action:@selector(stepChange:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:_stepper];
//高度不可变,宽度可变
_segControl=[[UISegmentedControl alloc] initWithFrame:CGRectMake(10, 200, 300, 40)];
[_segControl insertSegmentWithTitle:@"1" atIndex:0 animated:YES];
[_segControl insertSegmentWithTitle:@"2" atIndex:1 animated:YES];
[_segControl insertSegmentWithTitle:@"3" atIndex:2 animated:YES];
_segControl.selectedSegmentIndex=1;
[_segControl addTarget:self action:@selector(segChange:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:_segControl];
两个函数
-(void) segChange:(UISegmentedControl*) seg
{
NSLog(@"%ld",_segControl.selectedSegmentIndex);
}
-(void) stepChange:(UIStepper*) step
{
_label.text=[NSString stringWithFormat:@"%f",_stepper.value];
}
iOS第六课 NSArray与NSMutableArray
什么是NSArray
NSArray是OC中的数组类,开发中建议尽量使用NSArray替代C语言中的数组
NSArray的特点
- 只能存放任意OC对象, 并且是有顺序的
- 不能存储非OC对象,比如 int \ float \ double \ char \ enum \ struct等
- 它是不可变的,一旦初始化完毕后,它里面的内容就永远是固定的,不能删除里面的元素,也不能再往里面添加元素
- NSArray使用NSLog()打印,输出的是小括号的格式。
- NSArray中不能存储nil,因为NSArray认为nil是数组的结束(nil是数组元素结束的标记)。nil就是0,0也是基本数据类型,不能存放到NSArray中。
NSArray的常用方法
获取集合元素个数
-(NSUInteger)count;
获得index位置的元素
- (id)objectAtIndex:(NSUInteger)index;
是否包含某一个元素
- (BOOL)containsObject:(id)anObject;
返回最后一个元素
- (id)lastObject;
返回最后一个元素
- (id)firstObject;
查找anObject元素在数组中的位置(如果找不到,返回-1)
- (NSUInteger)indexOfObject:(id)anObject;
在range范围内查找anObject元素在数组中的位置
- (NSUInteger)indexOfObject:(id)anObject inRange:(NSRange)range;
书写NSArray简写形式
NSArray *arr = [NSArray arrayWithObjects:@"lnj", @"lmj", @"jjj", nil];
NSArray *arr = @[@"lnj", @"lmj", @"jjj"];
// 获取数组元素的简写
NSLog(@"%@", [arr objectAtIndex:0]);
NSLog(@"%@", arr[0]);
NSArray遍历
增强for 循环的使用
如何使用增强for循环,遍历NSArray数组
//逐个取出arr中的元素, 将取出的元素赋值给obj
// 注意: obj的类型可以根据数组中元素的类型来写, 不一定要写NSObject
for (NSString *obj in arr) {
NSLog(@"obj = %@", obj);
}
如何使用OC数组的迭代器来遍历数组
// 每取出一个元素就会调用一次block
// 每次调用block都会将当前取出的元素和元素对应的索引传递给我们
// obj就是当前取出的元素, idx就是当前元素对应的索引
// stop用于控制什么时候停止遍历
[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (idx == 1) {
*stop = YES;
}
NSLog(@"obj = %@, idx = %lu", obj, idx);
}];
数组排序
如何对数据进行排序
NSArray *arr = @[@10, @20, @5, @7, @15];
NSLog(@"排序前: %@", arr);
// 注意: 想使用compare方法对数组中的元素进行排序, 那么数组中的元素必须是Foundation框架中的对象, 也就是说不能是自定义对象
elector:@selectoNSArray *newArr = [arr sortedArrayUsingSr(compare:)];
NSLog(@"排序后: %@", newArr);
如何对对象进行排序
Person *p1 = [Person new];
p1.age = 10;
Person *p2 = [Person new];
p2.age = 20;
Person *p3 = [Person new];
p3.age = 5;
Person *p4 = [Person new];
p4.age = 7;
NSArray *arr = @[p1, p2, p3, p4];
NSLog(@"排序前: %@", arr);
// 按照人的年龄进行排序
// 该方法默认会按照升序排序
NSArray *newArr = [arr sortedArrayWithOptions:NSSortStable usingComparator:^NSComparisonResult(Person *obj1, Person *obj2) {
// 每次调用该block都会取出数组中的两个元素给我们
// 二分
// NSLog(@"obj1 = %@, obj2 = %@", obj1, obj2);
return obj1.age > obj2.age; //降序
// return obj1.age < obj2.age; //升序
/*
改方法,产生随机数用
if (obj1.age > obj2.age) {
// 5 4
return NSOrderedDescending;
}else if(obj1.age < obj2.age)
{
// 4 5
return NSOrderedAscending;
}else
{
return NSOrderedSame;
}
*/
}];
NSLog(@"排序后: %@", newArr);
NSArray和NSString转换
NSArray *arr = @[@"lnj", @"lmj", @"jjj"];
如何将数组中每个元素拼接成字符串
方法一:
// 1.定义一个可变字符串保存拼接之后的结果
NSMutableString *strM = [NSMutableString string];
// 2.遍历数组, 取出数组中的每一个元素, 将元素添加到可变字符串中
for (NSString *str in arr) {
[strM appendString:str];
// 3.每次添加完毕之后再添加一个-
[strM appendString:@"-"];
}
[strM deleteCharactersInRange:NSMakeRange(strM.length - 1, 1)];
NSLog(@"strM = %@", strM);
方法二:
//把数组元素链接成字符串,用**作拼接符将数组元素拼接成一个字符串
NSString *str = [arr componentsJoinedByString:@"**"];
NSLog(@"str = %@", str);
如何通过一个字符串生成一个数组
字符串分割方法
NSString *str = @"lnj**lmj**jjj";
NSArray *arr = [str componentsSeparatedByString:@"**"];
NSLog(@"arr = %@", arr);
NSArray文件读写
如何将数组写入文件中
NSArray *arr = @[@"lnj", @"lmj", @"jjj"];
BOOL flag = [arr writeToFile:@"/Users/xiaomage/Desktop/abc.plist" atomically:YES];
NSLog(@"flag = %i", flag);
将数组写入文件中,有什么注意点
- 如果将一个数组写入到文件中之后, 本质是写入了一个XML文件 在iOS开发中一般情况下我们会将XML文件的扩展名保存为plist
- writeToFile只能写入数组中保存的元素都是Foundation框架中的类创建的对象, 如果保存的是自定义对象那么不能写入
如何从文件中读取数据到NSArray中
从文件中读取一个数组,此方法在字典转模型中,经常用到
NSArray *newArray = [NSArray arrayWithContentsOfFile:@"/Users/xiaomage/Desktop/abc.plist"];
NSLog(@"%@", newArray);
NSMutableArray
可变数组 增删改查
什么是可变数组?和NSArray有什么区别
NSMutableArray是NSArray的子类;
NSArray是不可变的,一旦初始化完毕后,它里面的内容就永远是固定的, 不能删除里面的元素, 也不能再往里面添加元素;
NSMutableArray是可变的,随时可以往里面添加\更改\删除元素;
如何创建一个空的数组?创建可变数组有什么注意点?
1.创建空数组
NSMutableArray *arrM = [NSMutableArray array];
NSMutableArray *arrM = [[NSMutableArray alloc] init];
2.注意点:
不能通过@[]来创建一个可变数组, 因为@[]创建出来的是一个不可变的数组
如果把一个不可变数组当做一个可变数组来使用, 会引发一个运行时的错误
例如:
NSMutableArray *arrM = @[@"lnj", @"lmj"];
[arrM addObject:@"JJJ"];
如何给可变数组增加内容 方法一:
[arrM addObject:@"lnj"];
方法二:
// 将指定数组中的元素都取出来, 放到arrM中 \
并不是将整个数组作为一个元素添加到arrM中
[arrM addObjectsFromArray:@[@"lmj", @"jjj"]];
// 注意: 以下是将整个数组作为一个元素添加
// [arrM addObject:@[@"lmj", @"jjj"]];
NSLog(@"%@", arrM);
如何给可变数组插入内容
[arrM insertObject:@"xcq" atIndex:1];
NSRange range = NSMakeRange(2, 2);
NSIndexSet *set = [NSIndexSet indexSetWithIndexesInRange:range];
// 插入一组数据, 指定数组需要插入的位置, 和插入多少个
[arrM insertObjects:@[@"A", @"B"] atIndexes:set];
如何删除可变数组中的内容
删除指定元素:
[arrM removeObjectAtIndex:0];
删除数组中最后一个元素
[arrM removeLastObject];
删除index位置的元素
[arrM removeObject:@"A"];
如何替换可变数组中的内容
[arrM replaceObjectAtIndex:1 withObject:@"M"];
//简写:
arrM[0] = @"ZS";
NSLog(@"%@", arrM);
如何获取可变数组中的内容
NSLog(@"%@", [arrM objectAtIndex:0]);
第七课 NSCoder的用法
iOS对象序列化与反序列化( NScoder 和 NScoding )
面向对象的程序在运行的时候会创建一个复杂的对象图,经常要以二进制的方法序列化这个对象图,这个过程叫做Archiving. 二进制流可以通过网络或写入文件中(来源于某教材的一段话)
本人的理解是当你于写数据需要本地存储时,即将你的数据写到硬盘上的时候,你就必须对他进行序列化,转换成二进制文件,从而便于在磁盘上的读写,同理在取出的时候必须将其在反序列化,这样才能将数据读出来,就好比加密和揭秘的过程。
为什么我将数据写到plist 中的时候,也是存储到本地的磁盘上,但是我就没有序列化啊?
大家有没有发现,其实plist 的数据是类型是有限制的,就那么几种特定的数据类型,nsstring ,大家有没有尝试过将一个自己定义的类放进去(写进plist ),在读出来?
结果是什么大家可以先猜想。
其实在nsstring 的类的定义中已经添加了协议 即他是实现了nscoding 代理的方法的。
@interface NSString : NSObject
深入
NScoder 和 NScoding
NScoding 是一个协议,主要有下面两个方法
//从coder中读取数据,保存到相应的变量中,即反序列化数据
-(id)initWithCoder:(NSCoder *)coder;
// 读取实例变量,并把这些数据写到coder中去。序列化数据
-(void)encodeWithCoder:(NSCoder *)coder;
NSCoder 是一个抽象类,抽象类不能被实例话,只能提供一些想让子类继承的方法。
//从二进制流读取对象。
NSKeyedUnarchiver
//把对象写到二进制流中去。
NSKeyedArchiver
一个简单的例子
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
NSString *name;
char sex;
int age;
}
@property(nonatomic,copy) NSString *name;
@property char sex;
@property int age;
@end
person.m实现文件
#import "Person.h"
@implementation Person
@synthesize name,age,gender;
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:name forKey:@"stuName"];
NSNumber *age1 = [NSNumber numberWithInt:age];
[aCoder encodeObject:age1 forKey:@"stuAge"];
NSNumber *gender1 = [NSNumber numberWithChar:gender];
[aCoder encodeObject:gender1 forKey:@"stuGender"];
}
-(id)initWithCoder:(NSCoder *)dCoder
{
name = [dCoder decodeObjectForKey:@"stuName"];
age = [[dCoder decodeObjectForKey:@"stuAge"]intValue];
gender = [[dCoder decodeObjectForKey:@"stuGender"]charValue];
return self;
}
@end
main.m测试文件
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p1 = [[Person alloc]init];
p1.name = @"zhangsan";
p1.age = 22;
p1.gender = 'F';
Person *p2 = [Person new];
p2.name = @"lisi";
p2.age = 23;
p2.gender = 'M';
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:30];
[dic setObject:p1 forKey:@"person1"];
[dic setObject:p2 forKey:@"person2"];
//把字典内容存入到文件中
if ([NSKeyedArchiver archiveRootObject:dic toFile:@"/Users/mac/Desktop/a.plist"] ) {
NSLog(@"chenggong");
}
NSMutableDictionary *dic2 = [NSMutableDictionary dictionaryWithCapacity:30];
//从文件中读取内容放入到字典中
dic2 = [NSKeyedUnarchiver unarchiveObjectWithFile:@"/Users/mac/Desktop/a.plist"];
NSEnumerator *enumerator = [dic2 objectEnumerator];
id obj;
//遍历字典内容
while (obj = [enumerator nextObject]) {
NSLog(@"name = %@,age = %i,gender = %c",[obj name],[obj age],[obj gender]);
}
}
return 0;
}