1.自定义控件
a.继承某个控件
b.重写initWithFrame方法可以设置一些它的属性
c.在layoutsubviews添加子控件的重写frame
d.提供一个属性重写它的set方法
修饰符
用strong修饰OC对象以及NSString和Block ,没添加到父控件上的控件
用weak修饰已经被添加到父控件上的控件以及代理对象
用assign基本数据类型、枚举、结构体(非OC对象)class类型
用copy修饰一种情况下的NSString-->不确定赋值过程中用的是可变还是不可变字符串
2.简单的MVC
a.就是model模型vIewcontroll控制器view视图.
3.xib的创建和story的创建
加载xib的方式有
[nsbundlemainnbundle ]loadNibName:"文件名"options :nil];
4.通过纯代码创建的初始化一定会调用initWithFrame方法
通过xib的创建和story的创建的一定会调用aweakFromNib方法.
通过xib的创建对于它加载视图的时候会调用initWithCoder方法.
(1)awakeFromNib和initWithCoder:差别
awakeFromNib是初始化完毕调用并且从xib或者storyboard加载完毕就会调用
initWithCoder:只要对象是从文件解析来的,就会调用是初始化的时候调用
同时存在会先调用initWithCoder:
(2)initWithCoder: & initWithFrame:
initWithCoder:使用文件加载的对象调用(如从xib或stroyboard中创建)
initWithFrame:使用代码加载的对象调用(使用纯代码创建)
注意:所以为了同时兼顾从文件和从代码解析的对象初始化,要同时在initWithCoder:和initWithFrame:中进行初始化
5.拳皇设计的imageView的动画摇动bottomLeft出来mode
kvc和Kvo的区别:
kvc可以快速的字典转模型给私有的变量赋值给属性赋值也行
// KVO :键值监听
//作用:可以监听某个对象属性值的改变
/**
*给p对象添加一个监听器
*
*Observer:监听器(观察者)
*KeyPath :监听哪一个属性值的改变
*/
[p addObserver:selfforKeyPath:@"name"options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:@"asd"];
6.
在-(void)viewDidLoad里面调用
// self-sizing技术(iOS8开始支持的)
//告诉tableView所有cell的真实高度是自动计算的(根据你设置的约束计算)
self.tableView.rowHeight = UITableViewAutomaticDimension;
//告诉所有cell的估算高度
self.tableView.estimatedRowHeight =44;
if(status.isVip) {//是vip
self.vipImageView.hidden =NO;
self.nameLabel.textColor = [UIColor orangeColor];
}else{//不是vip
self.vipImageView.hidden =YES;
self.nameLabel.textColor = [UIColor blackColor];
}
if(status.picture) {//有配图
self.pictureImageView.hidden =NO;
self.pictureImageView.image = [UIImage imageNamed:status.picture];
self.pictureHeight.constant =100;
self.pictureBottom.constant =10;
}else{//没有配图
self.pictureImageView.hidden =YES;
self.pictureHeight.constant =0;
self.pictureBottom.constant =0;
}
6.静态cell:
当界面处于不改变的状态就是用静态cell
在做一些“死”页面的时候SB的静态cell是很好的选择,静态cell也不是什么都不能做,静态cell里的button还是可以拖到@implementation中形成IBAction的,但是是无法生成IBOutlet属性或字段的。
即使你强行的给一个静态的cell指定了一个cell的类,也是无法向其内部拖入IBOutlet的。这就是静态cell的局限性,但是如果你要设置的数据不多还是可以考虑用静态cell,因为你可以通过给cell上的控件设tag来找到它从而赋值。
7.问题1:简述registerNib:(nullableUINib *)nib forCellReuseIdentifier:(NSString *)identifier和registerClass:(nullableClass)cellClass forCellReuseIdentifier:(NSString *)identifier这2个方法的区别?
答:registerClass这个方法是根据ID注册对应的cell类型,系统创建cell的方式是通过alloc/initWithStyle...
registerNib这个方法是根据ID注册一个xib文件,系统创建cell的方式是通过加载xib文件.
问题2:如何计算一段文字的宽度和高度?
答:第一种情况:如果label只有一行,通过sizeWithAttributes:这个方法,告知这段文字的字体和字体大小就可以计算这段文件的尺寸.
第二种情况:如果label需要换行计算高度,通过boundingRectWithSize: options: attributes:attributes context:这个方法,告知这段文字的字体和字体大小,并且在一个限制的尺寸内计算这段文字的尺寸.
8.xib和storyBoard的创建:
1.xib创建的控制器首先要让这个控制器拥有一个View就是连线到View
2.直接加载[self.view addSubview:[[[NSBundle mainBundle]loadNibNamed:@"One"owner:selfoptions:nil]lastObject]];
storyboard创建的要给storyboard绑定标识其次在加载storyboardde视图
例如:
UIStoryboard *story =[UIStoryboard storyboardWithName:@"OYVC"bundle:nil];//qwer为标识符
[self.viewaddSubview:[story instantiateViewControllerWithIdentifier:@"qwer"].view];
9:为什么在遍历一个数组的时候,不能一边遍历一边删除,这样可能会导致什么问题?
因为再删除的同时遍历的下标将会随着改变这样就会导致数组遍历混乱.
10.通知
//创建通知
1.NSNotification *note = [NSNotification notificationWithName:@"军事新闻"object:comp1 userInfo:@{@"title":@"XXIIXIXIIXIXI"}];
//发布通知
2.[[NSNotificationCenter defaultCenter] postNotification:note];
1+2=[[NSNotificationCenter defaultCenter] postNotificationName:@"军事新闻"object:comp1 userInfo:@{@"title":@"XXIIXIXIIXIXIUIUIUIUIUIUIUIUI"}];
[[NSNotificationCenter defaultCenter] postNotificationName:@"娱乐新闻"object:comp2 userInfo:@{@"title":@"XXIIXIXIIXIXIUIUIUIUIUIUIUIUI"}];
//匿名通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"娱乐新闻"object:niluserInfo:@{@"title":@"XXIIXIXIIXIXIUIUIUIUIUIUIUIUI"}];
//接收通知
[[NSNotificationCenter defaultCenter] addObserver:p1 selector:@selector(getNews:) name:@"军事新闻"object:comp1];
[[NSNotificationCenter defaultCenter] addObserver:p2 selector:@selector(getNews:) name:@"娱乐新闻"object:nil];
// [[NSNotificationCenter defaultCenter] addObserver:p2 selector:@selector(getNews:) name:@"娱乐新闻" object:nil];
addObserver是接收通知者selector:@selector(getNews:)是通知要执行的方法name:@"军事新闻"是通知消息的名字object是参数
11.通知的使用
a.注册通知:[[NSNotificationCenter defaultCenter]postNotificationName:@"data"object:vc userInfo:@{@"mimi":self.textF.text}];
postNotificationName:消息的标识假如是nil的话相当于谁都可以接收消息object:是将要接收消息者是发出者userInfo:是你要传递的数据也可说是参数.
b.接收通知也就是注册通知
[[NSNotificationCenter defaultCenter]addObserver:selfselector:@selector(changeValue:) name:@"data"object:nil];
addObserver :是要接收通知者elector:@selector(changeValue:)传递数据的方法name:是消息的标识假如是nil的话就是什么消息都会接收object:是要发出者假如是nil的话谁的消息都会接收
3.这就是实现数据传递的方法:
-(void)changeValue:(NSNotification *)notification{
NSDictionary *dic = [notification userInfo];
NSString *str = [dic objectForKey:@"mimi"];
self.textF.text = str;
}
12.属性传递消息
接受者设置属性
同时在发出者有数据的时候将该数据的值赋值给该属性;
13.代理
1.设置一个协议并且要有一个传递数据的方法
2.发消息者设置一个代理属性
3.在接收消消息者和发消息者同时出现的时候设置代理并且接收者需要遵守该协议即发出者.delegate =接受者;
4.接收者实现数据传递的方法
5.发消息者调用实现数据传递的方法.
14.控制器跳转:
1.modal跳转
方法: presentViewController:/*需要跳转的控制器(nonnull UIViewController *) */animated:(YES) completion:^{
跳转之后执行的方法
}
通过dismissViewControllerAnimated来返回前一个界面的。这是返回前一个界面的.
2.push POP跳转
a.是给一根segua线绑定标识在获取跳转的目标控制器
//就是这种模式OYVC *vc = segue.destinationViewController;
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
OYVC *vc = segue.destinationViewController;
}
//再调用这个方法来实现跳转
- (IBAction)go:(id)sender {
[selfperformSegueWithIdentifier:@"go"sender:nil];
}
//用代码创建的
+ (instancetype)segueWithIdentifier:(nullableNSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination performHandler:(void(^)(void))performHandler NS_AVAILABLE_IOS(6_0);
- (instancetype)initWithIdentifier:(nullableNSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination NS_DESIGNATED_INITIALIZER;
b.回跳的话
[self.navigationController popViewControllerAnimated:YES];等方法
通过dismissViewControllerAnimated来返回前一个界面的。这是返回前一个界面的.也可以.
3、通过导航控制器UINavigationController
导航控制器:绝对是最常用的跳转方法,也是大家最熟悉的一种方式。每个控制器对象都有一个NavigationController属性,NavigationController的view的是由导航条,导航条控制的view,和栈顶控制器的view组成的。
工作原理:通过栈的方式的来实现的,NavigationController展示永远就是栈顶的控制器的view。当使用push方法的时候,就将需要跳转的控制器压入栈中,成为栈顶控制器;当使用pop方法的时候,就将控制器移出栈,原来跳转之前的控制器重新成为栈顶控制器,被展现;
需要注意的是:跳转的时候,跳转前的控制器不会移除;导航栏(UINavigationBar)的属性由栈顶控制器来决定。UINavigationBar支持appearance统一设置,但UINavigationItem不支持;
涉及到的类详解:
UINavigationBar :继承至UIView,NavigaitonBar就是导航栏,位于屏幕的上方,管理整个NavigationController的navigationItem,即类似navigationcontroller一样提供了一个栈来管理item。
UINavigationItem :继承至NSObject,通过这个属性来设置title,prompt,leftBarButtonItem,titleView,,rightBarButtonItem,backBarButonItem等。
UIBarButtonItem :继承至UIBarItem,UIBarItem继承至UIButton。专门用来放在UIToolbar或者UINavigationBar的特殊button。
总结:NavigationController直接控制ViewControllers,并包含NavigaitonBar。NavigaitonBar包含整个UINavigationItem的栈,管理整个NavigationController的UINavigationItem(NSArray *items属性)。UINavigationItem包含了NavigaitonBar视图的全部元素(如title,tileview,backBarButtonItem等),又受当前栈顶控制器管理,即NavigaitonBar形成整个NavigationController的导航视图,然后每个NavigationController页面的导航栏元素由所在页面的UINavigationItem管理。即设置当前页面的左右barbutton。
4、UITabBarController
tabbar控制器,同样是常用的界面切换方式,一般作为app的根界面的视图控制器。其实与其说UITabBarController的界面跳转,不如说是界面切换,因为UITabBarController的界面跳转其实就是UITabBarController的viewControllers数组中的几个界面切换。只要设置好了UITabBarController的viewControllers数组就可以了。也可以工厂自定义tabbar,通过selectedItem来控制。
结构也类似NavigationController
tableBar的添加底部的控制器有View Controllers添加子控制器.
15.通过storyboard加载控制器的方法
// Name:storyboard文件名
// nil = [NSBundle mainBundle]
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main"bundle:nil];
//加载Main.storyboard描述的控制器
// instantiateInitialViewController:加载箭头指向的控制器
UIViewController *vc = [storyboard instantiateInitialViewController];
/通过xib加载控制器的步骤
// 1.创建xib文件
// 2.xib拖一个view去描述控制器的view!!!!!重点
// 3.告诉xib是描述控制器,设置file'owner为控制器,可以往控制器中拖线
// 4.连线,告诉控制器哪个view描述你的view
16.pch原理:会把pch里面的所有内容导入到每个文件中去
pch作用:
1.pch存放公用的宏
2.pch存放公用的头文件,分类的头文件
3.pch可以自定义Log
pch注意点:
判断下当前是否是OC文件
*/
//每一个OC文件都会定义这个宏__OBJC__
#ifdef __OBJC__
//放OC
#import"UIImage+Image.h"
#define ABC 10
//判断系统的版本号
#define iOS8([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)
#define iPhone5 ([UIScreen mainScreen].bounds.size.height == 568)
//程序在调试阶段的时候才需要打印
#ifdef DEBUG//调试阶段
// ...表示宏里面的可变参数
// __VA_ARGS__函数里面可变参数
#define XMGLog(...)NSLog(__VA_ARGS__)
#else//发布阶段
#define XMGLog(...)
#endif
16.日期的格式
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat =@"yyyy-MM-dd";
NSDate *date = [fmt dateFromString:@"1990-1-1"];
方法自己摸索一步步去理解
17.开启上下文模式(Quartz2D)
Quartz提供了5种类型的Graphics Context。Bitmap Graphics Context、PDF Graphics Context、Window Graphics Context、Layer Context、Post Graphics Context。
a.图形上下文
一定会执行drawRect方法并且还要重绘[selfsetNeedsDisplay].
1.获得图形上下文2.设置绘画路径3将路径描述好4将路径添加到上下文中5将上下文渲染到图中
// 1.获取上下文
CGContextRef ctx= UIGraphicsGetCurrentContext();
// 2.设置绘图信息/拼接路径
UIBezierPath *path = [UIBezierPath bezierPath];
// 3.设置一个起点
[path moveToPoint:CGPointMake(10,10)];
// 4.添加一条直线到一个点
[path addLineToPoint:CGPointMake(100,100)];
// 5.添加一条直线到一个点
[path addLineToPoint:CGPointMake(150,60)];
// 5.把路径添加到上下文
CGContextAddPath(ctx, path.CGPath);
// 6.把上下文渲染到视图
CGContextStrokePath(ctx);
// stroke:描边
// fill:填充
//设置线的样式
CGContextSetLineJoin(ctx, kCGLineJoinBevel);
//设置顶角样式
CGContextSetLineCap(ctx, kCGLineCapRound);
Current transformation matrix (CTM):当前转换矩阵
Clipping area:裁剪区域
Line:线
Accuracy of curve estimation (flatness):曲线平滑度
Anti-aliasing setting:反锯齿设置
Color:颜色
Alpha value (transparency):透明度
Rendering intent:渲染目标
Color space:颜色空间
Text:文本
Blend mode:混合模式
CGPathRef:用于向量图,可创建路径,并进行填充或描画(stroke)
CGImageRef:用于表示bitmap图像和基于采样数据的bitmap图像遮罩。
CGLayerRef:用于表示可用于重复绘制(如背景)和幕后(offscreen)绘制的绘画层
CGPatternRef:用于重绘图
CGShadingRef、CGGradientRef:用于绘制渐变
CGFunctionRef:用于定义回调函数,该函数包含一个随机的浮点值参数。当为阴影创建渐变时使用该类型
CGColorRef, CGColorSpaceRef:用于告诉Quartz如何解释颜色
CGImageSourceRef,CGImageDestinationRef:用于在Quartz中移入移出数据
CGFontRef:用于绘制文本
CGPDFDictionaryRef,CGPDFObjectRef,CGPDFPageRef,CGPDFStream, CGPDFStringRef, and CGPDFArrayRef:用于访问PDF的元数据
CGPDFScannerRef, CGPDFContentStreamRef:用于解析PDF元数据
CGPSConverterRef:用于将PostScript转化成PDF。在iOS中不能使用。
2.位图上下文:
// 1.开启上下文
UIGraphicsBeginImageContextWithOptions(view.bounds.size,NO,0.0);
// 2.获取当前上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 3.把控制器图层渲染到上下文
[view.layer renderInContext:ctx];
// 4.取出新图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//图片保存到本地相册的方法:::
UIImageWriteToSavedPhotosAlbum(newImage,self,@selector(image:didFinishSavingWithError:contextInfo:),nil);
//当写入完成时调用即是照片读取完毕后会进来
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void*)contextInfo {
NSLog(@"saveCom");
}
- (IBAction)photo:(id)sender {
//弹出系统相册选择照片
UIImagePickerController *pickVC = [[UIImagePickerController alloc] init];
//设置照片来源
pickVC.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
//只要实现代理方法,必须得要手去关闭控制器
pickVC.delegate =self;
//modal
[selfpresentViewController:pickVC animated:YEScompletion:nil];
}
//选择照片完毕后会进来
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSLog(@"%@",info);
UIImage *image = info[UIImagePickerControllerOriginalImage];
//NSData *data = UIImagePNGRepresentation(image);
//[data writeToFile:@"/Users/apple/Desktop/choose.png" atomically:YES];
HanleImageUIView *hanleV = [[HanleImageUIView alloc] init];
hanleV.frame =self.drawView.frame;
hanleV.backgroundColor = [UIColor clearColor];
hanleV.image = image;
hanleV.delegate =self;
[self.view addSubview:hanleV];
//把选择图片绘制画板当中
//self.drawView.image = image;
[selfdismissViewControllerAnimated:YEScompletion:nil];
}
18.cell释放池的问题cell能够重复利用
当前tableview界面当当一个消失后一个出现的时候后一个的内存地址就是第一个的内存地址这样就解决了内存地址的问题就会有重用机制这样的话内存就会大大的减少
//cell的创建系统的释放池内
UITableViewCell *cell= [tableView dequeueReusableCellWithIdentifier:ID];
//判断释放池内有没有cell
//第一种方式
if( !cell ) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ID];
}
//第二种注册的方式
1.类的注册
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:ID];
2.xib的注册
[self.tableView registerNib:<#(nullable UINib *)#> forCellReuseIdentifier:ID];
//第三种是自己自定义cell可以在xib或者storyBoard里面设置cell的标识
//分割线颜色
self.tableView.separatorColor = [UIColor redColor];
//隐藏分割线
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
//自定义不等高cell的做法
在模型中增加一个cellHeight属性,用来存放对应cell的高度
在cell的模型属性set方法中调用[selflayoutIfNeed]方法强制布局,然后计算出模型的cellheight属性值
在控制器中实现tableView:estimatedHeightForRowAtIndexPath:方法,返回一个估计高度,比如200
在控制器中实现tableView:heightForRowAtIndexPath:方法,返回cell的真实高度(模型中的cellHeight属性
19.单粒单例模式的替代一劳永逸
#define SingleH(name) +(instancetype)share##name;
#if __has_feature(objc_arc)
///ARC
#define SingleM(name) static id_instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
return _instance;\
}\
+(instancetype)share##name\
{\
return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
\
-(id)mutableCopyWithZone:(NSZone *)zone\
{\
return _instance;\
}
#else
//MRC
#define SingleM(name) static id_instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
return _instance;\
}\
+(instancetype)share##name\
{\
return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
\
-(id)mutableCopyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
-(oneway void)release\
{}\
\
-(instancetype)retain\
{\
return _instance;\
}\
\
-(NSUInteger)retainCount\
{\
return MAXFLOAT;\
}
#endif
19.沙盒
Documents :会备份&不允许(X)//很重要
Library
caches
perference偏好设置
tmp :临时数据
4.数据存储
1.Documents
获取方法:NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask,YES)[0];
//存放重要数据.iTunes同步设备时会备份
2.tmp
获取方法:NSTemporaryDirectory();
//存放临时文件,系统会随机删除
3.Caches
获取方法:NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask,YES)[0];
//存放大体积,不必要备份文件
4.Preferences
获取方法:[NSUserDefaults standardUserDefaults]
//存放少量数据.iTunes同步设备时会备份
2.数据存储
1.plist
pilst只支持系统自带的类型(如:NSString,NSArray,NSDictionary,NSData,NSNumber等)
1.写入:writeToFile
2.读取:...WithContentOfFile(如:arrayWithContentOfFile)
2.偏好设置
1.取得偏好设置对象(NSUserDefaults)
NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
2.写入到文件夹
[def setObject:obj forKey:key];//oc类对应setObject,bool类型对应setBool等...
3.读取内容
[def objectForKey:obj];//oc类对应object,NSInteger对应integer等...
3.归档
1.写入用NSKeyedArchjver
1.选择要存储的位置(filePath)
2.系统自带类(如:NSArray,NSDictionary)直接使用
3.自定义类需遵守NSCoding协议,并重写encodeWithCoder方法(例子为name属性)
-(void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.name forKey:@"name"];
}
4.调用[NSKeyedArchjver archiveRootObject:object toFile:filePath];
2.读取用NSKeyedUnArchjver
1.获取要读取文件的位置(filePath)
2.系统自带类(如:NSArray,NSDictionary)直接使用
3.自定义类需遵守NSCoding协议,并重写initWithCoder方法(例子为name属性)
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
if(self= [superinit]){
self.name = [aDecoder decodeObjectForKey:@"name"];
}
returnself;
}
4.调用[NSKeyedUnArchjver unarchiveObjectWithFile:filePath]
归档:自定义对象一般使用归档,为什么自定义对象需要归档,plist存储不能存储自定义对象其实际操作跟字典差不多就是得遵守nscoding的协议
- (void)encodeWithCoder:(NSCoder *)aCoder;
- (nullableinstancetype)initWithCoder:(NSCoder *)aDecoder;
假如你要存档和解档的话都要写这两个方法方法也要看着属性的类型进去解归档.
要使用归档的话都要遵守nscoding这个协议
首先进行保存的操作:就是将数据读取进去假如写入模型的时候要进行一
如何进行解档的操作
解析文件的时候调用
//作用:解析xib,storyboard调用
- (id)initWithCoder:(NSCoder *)aDecoder
{
//这里必须调用[super initWithCoder:aDecoder],super ->UIView
//什么时候调用[super initWithCoder:aDecoder],只要父类遵守了NSCoding协议,就调用[super initWithCoder:aDecoder]
if(self= [superinitWithCoder:aDecoder]) {
NSLog(@"%s",__func__);
}
returnself;
}
20.下载图片的整体思路:
1.首先判断内存缓存有没有图片2假如没有的话就要保存到内存中3在保存中还要看它有没有在子线程中如果在的话啥都不做不在的话就要创建子线程将图片下载的过程加到子队列中而且还要检查图片是不是为空不然的话会一直有任务在进行就会一直开子进程在子进程中还要跳转到主进程去显示图片最后将子进程添加到队列中并且保存队列到字典中去进行下一次判断子进程还要不要开就是执行中任务有没有不然会造成任务多次运行.
//假如图片为空的话移除所有队列里面的加载
if(newImage ==nil) {
[self.opearations removeObjectForKey:item.icon];
}
[self.images setValue:newImage forKey:item.icon];
[data writeToFile:filePath atomically:YES];
//刷新tabelView的方法
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self.tableView reloadRowsAtIndexPaths:@[indexPath]withRowAnimation:UITableViewRowAnimationTop];
}];
1)UI卡顿--->开子线程下载图片
图片不显示(fram=0)--->刷新指定的行
重复下载的问题(因为图片下载操作需要花费时间,在该时间段内部此image有需要显示)
对图片的下载操作进行缓存--->操作缓存
2)重复下载的问题-->内存缓存
*/
//二级缓存
/*
显示-->内存缓存-->下载
显示-->内存缓存-->磁盘缓存-->下载
*/
21.SDWebImage下载图片框架的作用:
1).为cocoa touch提供一个UIimageView的分类,加载图片并进行缓存处理
2).异步下载图片
3).异步存储器+具备自动缓存过程处理的磁盘映像缓存
4).支持GIF播放
5).支持WebP格式
6).背景图片解压缩
7).保证同一个图片Url不被多次下载
8).保证错误的URL不被反复下载
9).保证不会阻塞主线程
10).高性能
11).使用GCD和ARC机制
12).支持Ara64架构
/*
1)clear先把之前的缓存文件夹删除,然后重新创建一个新的文件夹是暴力删除
clean先删除过期的文件,然后计算剩余缓存文件的大小(currrentSize)>maxSize,继续删除(按照缓存文件创建的时间顺序来删除的),直到currrentSize <= maxSize
2)默认过期时间:1个星期
3)内存缓存机制(用什么来做内存缓存?是字典吗?) NSCache是专门用来做缓存处理的
4)最大并发数量maxConcurrentOperationCount = 6
5)队列中任务的执行方式:
SDWebImageDownloaderExecutionOrder
SDWebImageDownloaderFIFOExecutionOrder(FIFO)默认
SDWebImageDownloaderLIFOExecutionOrder(lIFO)(通过设置依赖来实现)
6)默认的缓存路径:~/Library/Caches/default/com.hackemist.SDWebImageCache.default/...
7)图片保存的名称处理方式:url进行MD5加密echo -n "url" | md5
8)播放GIF图片, GIF图片播放原理ImageIO
9)如何判断图片的类型:得到图片的二进制数据的第一个字节
10)该框架内部通过NSURLConnection建立网络连接发送请求下载图片
11)默认的请求超时的时间是_downloadTimeout = 15
12)该框架内部对内存警告的处理方式:内部会监听系统发出的系统警告通知,然后清理内存缓存
13)NSCache使用方法和可变的字典类似(80%),线程安全&可以自动的清理缓存数据
14)计算图片的成本:image.size.height * image.size.width * image.scale * image.scale
15)保证错误url不被反复尝试下载?内部设置了一个url黑名单NSMutableSet
*/
下载图片框架的使用:
1.1)下载图片并显示(内存缓存&磁盘缓存)
/*
第一个参数:图片的url地址
第二个参数:设置的占位图片
*/
[self.imageView sd_setImageWithURL:[NSURL URLWithString:URL] placeholderImage:[UIImage imageNamed:image]];
2.下载图片显示并计算下载进度(内存缓存&磁盘缓存&下载进度)
/*
第一个参数:图片的url地址
第二个参数:设置的占位图片
第三个参数:下载图片选项(策略)
第四个参数:进度回调blockreceivedSize:已经下载的数据大小expectedSize:图片的总大小
第五个参数:completed图片下载结束回调(成功|失败)
image:下载后得到的图片,如果下载失败,那么image的值为nil
error:错误信息,如果失败,则error有值
cacheType:图片来源(枚举:内存缓存|磁盘缓存|直接下载)
imageURL:下载图片的url
*/
sd_setImageWithURL:[NSURL URLWithString:url]placeholderImage:[UIImage imageNamed:占位图片] options:SDWebImageProgressiveDownload progress:^(NSInteger receivedSize, NSInteger expectedSize) {
NSLog(@"%f",1.0* receivedSize/expectedSize);//进度值得算法
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
}
3)下载图片不显示并监听下载进度(内存缓存&磁盘换次&下载进度)
-(void)download3
{
//使用管理者下载图片
[[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString:URL] options:0progress:^(NSInteger receivedSize, NSInteger expectedSize) {
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType,BOOLfinished, NSURL *imageURL) {
NSLog(@"+++++%@",[NSThread currentThread]);
self.imageView.image = image;
switch(cacheType) {
caseSDImageCacheTypeNone:
NSLog(@"直接下载");
break;
caseSDImageCacheTypeDisk:
NSLog(@"磁盘缓存");
break;
caseSDImageCacheTypeMemory:
NSLog(@"内存缓存");
break;
default:
break;
}
}];
}
4)下载图片不显示且不做任何的缓存处理
-(void)download4
{
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:[NSURL URLWithString:动图的URL ] options:0progress:^(NSInteger receivedSize, NSInteger expectedSize) {
NSLog(@"%f",1.0* receivedSize/expectedSize);
} completed:^(UIImage *image, NSData *data, NSError *error,BOOLfinished) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = [UIImage sd_animatedGIFWithData:data];
}];
}];
}
5)接收到系统级内存警告时如何处理(面试)
//(1)取消当前正在进行的所有下载操作
[[SDWebImageManager sharedManager] cancelAll];
//(2)清除缓存数据
//cleanDisk:删除过期的文件数据,计算当前未过期的已经下载的文件数据的大小,如果发现该数据大小大于我们设置的最大缓存数据大小,那么程序内部会按照按文件数据缓存的时间从远到近删除,知道小于最大缓存数据为止。
//clearMemory:直接删除文件,重新创建新的文件夹
//[[SDWebImageManager sharedManager].imageCache cleanDisk];
[[SDWebImageManager sharedManager].imageCache clearMemory];
6)播放gif图片
(1)播放GiF图片部分过程解析
a.把用户传入的gif图片->NSData
b.根据该Data创建一个图片数据源(NSData->CFImageSourceRef)
c.计算该数据源中一共有多少帧,把每一帧数据取出来放到图片数组中
d.根据得到的数组+计算的动画时间-》可动画的image
e.[UIImage animatedImageWithImages:images duration:duration];
(2)如何使用
-(void)gif
{
//self.imageView.image = [UIImage imageNamed:@"123"];不可用
UIImage *image = [UIImage sd_animatedGIFNamed:@"123"];
self.imageView.image = image;
}
22.NSCache与NSDictionary的对比:要遵守代理的哦
1.NSCache可以设置代理
2.NSCache可以设置缓存的成本即当超过了这个成本的时候会自动删除从前往后删.
3.NSCache的线程是安全的
totalCostLimit:缓存空间的最大总成本,超出上限会自动回收对象。默认值为0,表示没有限制
countLimit:能够缓存的对象的最大数量。默认值为0,表示没有限制
evictsObjectsWithDiscardedContent:标识缓存是否回收废弃的内容
//NSCache的基本使用(如何存数据|如何取数据)~和可变字典类似
当内部开始清理数据的时候调用
-(void)cache:(NSCache *)cache willEvictObject:(id)obj;
23.新版本特性界面控制器
1.根据对应版本号来确定是否新特性界面控制器
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
//2.设置根控制器
//2.1根据当前版本和上一次的版本进行判断
//2.2获取当前版本号
NSString *curVersion = [NSBundle mainBundle].infoDictionary[@"CFBundleShortVersionString"];
//2.3获取上一次的版本号
NSString *lastVersion = [[NSUserDefaults standardUserDefaults]objectForKey:@"version"];
//2.4根据比较确定是否存储版本
if([curVersion isEqualToString:lastVersion]) {
XMGMainVc *mainVc = [[XMGMainVc alloc]init];
self.window.rootViewController = mainVc;
//
}else{//存储版本,当前版本和上一次不一样,显示新特性界面
NSUserDefaults *defaultData = [NSUserDefaults standardUserDefaults];
[defaultData setObject:curVersion forKey:@"version"];
[defaultData synchronize];
XMGNewFeatureVc *newVc = [[XMGNewFeatureVc alloc]init];
self.window.rootViewController = newVc;
}
//3.可见
[self.window makeKeyAndVisible];
24.位移枚举
1.//纯C语言风格
typedefenum: NSUInteger {
MyEnumValueA,
MyEnumValueB,
MyEnumValueC,
} myType;
//纯OC语言风格
typedefNS_ENUM(NSUInteger, myOCType) {
MyEnumValue1,
MyEnumValue2,
MyEnumValue3,
};
//位移枚举
typedefNS_OPTIONS(NSUInteger, myWeiYiType) {
MyEnumValueA1 =1<<0,
MyEnumValueB2 =1<<1,
MyEnumValueC3 =1<<2,
};
2.位移枚举相关说明
特点:通过使用位移枚举可以实现一个参数实现传递多个操作
原理:按位与只要有0则为0,按位或只要有1则为1
技巧:如果位移枚举的第一个选项为0,那么在传递参数的时候默认可以传0,传0性能最优,不做额外的操作
25.NSTimer和GCD的定时器有什么区别?
1.GCD的定时器比nstimer更加精确
2.GCD的定时器不用依赖runloop而nstimer没有加入到runloop中将不会运行
3.[NSTimer scheduledTimerWithTimeInterval:3.0target:selfselector:@selector(task) userInfo:nilrepeats:YES];//默认已经添加到runloop中
假如不用这个方法就要加到runLoop中;
4.
//1.创建一个GCD的定时器
/*
第一个参数:DISPATCH_SOURCE_TYPE_TIMER定时器
第二个参数:描述信息
第三个参数:总是穿0
第四个参数:队列(决定GCD要执行的任务在哪个线程中调用的并发队列--子线程中调用)
*/
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,0,0, dispatch_get_main_queue());
//2.设置定时器
/*
第一个参数:定时器对象
第二个参数:从什么时候开始计时DISPATCH_TIME_NOW现在
第三个参数:间隔时间2.0 ns
第四个参数:精准度允许的误差绝对精准~0
*/
//dispatch_time_t t = dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC);
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW,2.0* NSEC_PER_SEC,0* NSEC_PER_SEC);
//3.设置定时器的任务
dispatch_source_set_event_handler(timer, ^{
NSLog(@"==GCD===%@",[NSThread currentThread]);//任务块
});
//4.恢复定时器
dispatch_resume(timer);
//一定要这句要强应用它不然创建的定时器对象就会挂掉
self.timer = timer;
26.Runloop原理:
1.程序一启动就会有一个主runloop开启
2)在iOS开发中有两套api来访问Runloop
a.foundation框架[NSRunloop]
b.core foundation框架[CFRunloopRef]互换的格式是例如: mainRunloop.getCFRunLoop
2./子线程和runloop的关系
/*
1)一一对应的
2)主线程对应的runloop默认已经开启了,子线程对应的runloop需要主动创建
3)如何创建子线程对应的runloop :[NSRunLoop currentRunLoop](该方法本身是懒加载的,第一次调用该方法的时候如果发现runloop不存在那么会直接创建一个)
4)runloop是需要开启
*/
3.a.CFRunloopRef//创建runloop对象
b.CFRunloopModeRef【Runloop的运行模式】
c.CFRunloopSourceRef【Runloop要处理的事件源】
d.CFRunloopTimerRef【Timer事件】
e.CFRunloopObserverRef【Runloop的观察者(监听者)】
注意点:
01.CFRunloopModeRef代表着Runloop的运行模式
02.一个Runloop中可以有多个mode,一个mode里面又可以有多个source\observer\timer等等
03.每次runloop启动的时候,只能指定一个mode,这个mode被称为该Runloop的当前mode
04.如果需要切换mode,只能先退出当前Runloop,再重新指定一个mode进入
05.这样做主要是为了分割不同组的定时器等,让他们相互之间不受影响
06.系统默认注册了5个mode
a.kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
b.UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时不受其他Mode影响
c.UIInitializationRunLoopMode:在刚启动App时第进入的第一个Mode,启动完成后就不再使用
d.GSEventReceiveRunLoopMode:接受系统事件的内部Mode,通常用不到
e.kCFRunLoopCommonModes:这是一个占位用的Mode,不是一种真正的Mode
CFRunLoopObserverRef//观察者
这个仅供内部参考实际开发中基本用不到
1.创建监听者
/*
第一个参数:分配存储空间
第二个参数:告知要监听的是哪种状态
第三个参数:持续监听runloop状态
第四个参数:优先级0
第五个参数:activity runloop当前的状态
*/
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities,YES,0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
/*
kCFRunLoopEntry = (1UL << 0),进入
kCFRunLoopBeforeTimers = (1UL << 1),即将处理timer事件
kCFRunLoopBeforeSources = (1UL << 2),将处理soure事件
kCFRunLoopBeforeWaiting = (1UL << 5),即将进入休眠
kCFRunLoopAfterWaiting = (1UL << 6),被唤醒
kCFRunLoopExit = (1UL << 7),runloop退出
kCFRunLoopAllActivities = 0x0FFFFFFFU
*/
2.给对应的runloop添加监听者并且制定监听的是哪种运行模式
/*
第一个参数:runloop对象本身
第二个参数:监听者(观察者)
第三个参数:runloop的运行模式
*/
CFRunLoopAddObserver(CFRunLoopGetCurrent(),observer, kCFRunLoopDefaultMode);
4.Runloop应用
1)NSTimer
2)ImageView显示:控制方法在特定的模式下可用
3)PerformSelector
4)常驻线程:在子线程中开启一个runloop
5)自动释放池
第一次创建:进入runloop的时候
最后一次释放:runloop退出的时候
//其它创建和释放:当runloop即将休眠的时候会把之前的自动释放池释放,然后重新创建一个新的释放池//????
27.自定义转场动画:
1.在要跳转的控制器实现系统跳转
ZJViewController *zjVc = [[ZJViewController alloc] init];
[selfpresentViewController:zjVc animated:YEScompletion:nil];
2.给要跳转的控制器设置代理为self,设置跳转方式为UIModalPresentationCustom
zjVc.modalPresentationStyle = UIModalPresentationCustom;
zjVc.transitioningDelegate =self;
3.遵守UIViewControllerTransitioningDelegate协议,实现方法
- (nullableUIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source{
return[[UIPresentationController alloc] initWithPresentedViewController:presented presentingViewController:presenting];
}
4.需实现UIPresentationController里的方法,继承自UIPresentationController写一个自己的跳转控制器
//这里为ZJPresentationController
将第3步返回的对象改为这种类型
return[[ZJPresentationController alloc] initWithPresentedViewController:presented presentingViewController:presenting];
5.实现跳转控制器(ZJPresentationController)的方法
- (void)containerViewWillLayoutSubviews{
//设置控制器的大小位置,不设置不会显示出来
self.presentedView.frame =self.containerView.bounds;
}
- (void)presentationTransitionWillBegin{
[self.containerView addSubview:self.presentedView];
}
- (void)dismissalTransitionDidEnd:(BOOL)completed{
[self.presentedView removeFromSuperview];
}
6.设置动画的代理
只要遵守了UIViewControllerAnimatedTransitioning协议的都可以(复杂时新建一个对象专门管理动画)
- (nullableid)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:
//返回控制器弹出时动画的代理
- (nullableid)animationControllerForDismissedController:(UIViewController *)dismissed
//返回控制器销毁时动画的代理
7.代理中实现动画方法
- (void)animateTransition:(id)transitionContext
如果控制器弹出,销毁都有动画,则需声明一个属性来记录弹出还是销毁状态
@property(nonatomic,assign)BOOLpresented;
并且在第6步中返回时给这个代理的presented属性赋值(YES/NO)
然后根据这个属性来做动画
[transitionContext viewForKey:UITransitionContextToViewKey];
//获取弹出时的view
[transitionContext viewForKey:UITransitionContextFromViewKey]
//获取销毁时的view
[transitionContext completeTransition:YES];
//动画完成时一定要通知系统
假如要在首层disMiss掉需要通过创建手势的方法
[self.presentedVC disMiss........]
拦截手势的方法首先遵守手势代理设置代理实现代理方法在代理方法中确定手势的范围.
cgpoint Point = [touch locationinView:手势的View];
BOOLpresent = CGRectContainsPoint(self.presentedView.frame, point);
28.控制器的生命周期的方法以及调用的顺序
//当控制器View加载完毕时调用
- (void)viewDidLoad {
[superviewDidLoad];
NSLog(@"%s",__func__);
}
一般调用一次
//当控制器View即将显示时调用
- (void)viewWillAppear:(BOOL)animated {
[superviewWillAppear:animated];
NSLog(@"%s",__func__);
}
//当控制器View显示完毕时调用
- (void)viewDidAppear:(BOOL)animated {
[superviewDidAppear:animated];
NSLog(@"%s",__func__);
}
//当控制器View即将布局子控件时调用
- (void)viewWillLayoutSubviews {
[superviewWillLayoutSubviews];
NSLog(@"%s",__func__);
}
//当控制器View布局子控件完毕时调用
- (void)viewDidLayoutSubviews {
[superviewDidLayoutSubviews];
NSLog(@"%s",__func__);
}
//当控制器View既将消失时调用
- (void)viewWillDisappear:(BOOL)animated {
[superviewWillDisappear:animated];
NSLog(@"%s",__func__);
}
//当控制器View消失完毕时调用
- (void)viewDidDisappear:(BOOL)animated {
[superviewDidDisappear:animated];
NSLog(@"%s",__func__);
}
29.控制器的跳转的方式以及数据传递的方式
1.手动创建是由一个view跳转到另外一个view;必须有标识符的
2.用代码根据标识去跳转
3.自动创建是直接跳转的点击控件自动转到下一个控制器
4.数据传递的方式正向传递和逆向传递
5.正向传递
[[NSNotificationCenter defaultCenter]addObserver:selfselector:@selector(textChange) name:nilobject:self.accountTextF]
observer :
name:是通知的名字
object:是发通知的的人
selector :是方法
代理:
1.代理者:接收消息的人
2.被代理者:是发消息的人'
3.属性:定义属性@property(nonatimic,strong)id<协议名称>属性名称;
4.调用代理;
1.plist
1.1tmp:
1.2doucument
block的做法
//起别名
typedefvoid(^contanctBlock ) (XMGContactItem *);
//属性
@property(nonatomic,copy)contanctBlock contactBlock;
调用block
if(self.contactBlock) {
self.contactBlock(item);
}
//在跳转前之前会调用这个方法
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
XMGAddVC_3 *addVC = segue.destinationViewController;
addVC.contactBlock = ^(XMGContactItem *item){
//实现代码
//2.1添加数据
[self.dataArray addObject:item];
//2.2刷新
[self.tableView reloadData];
};
}
30.UINavigationController(顶部导航条控制器)
1.代码创建并设UINavigationController为window的跟控制器
在AppDelegate的didFinishLaunchingWithOptions方法中
1.创建window
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
2.创建UINavigationController并设置根控制器
UIViewController *vc = [[UIViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
self.window.rootViewController = nav;
3.显示window
[self.window makeKeyAndVisible];
//注意:需要将info.plist中的storyboard选项删除
2.控制器之间的跳转(先放的控制器在栈底,只能从顶部往下移除控制器)
1.push跳转(往栈中放一个控制器)
UIViewController *vc = [UIViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
2.pop跳转
1.跳转到上一个控制器(移除顶部的控制器)
[self.navigationController popViewControllerAnimated:YES];
2.跳转到根控制器(移除根控制器以外所有控制器)
[self.navigationController popToRootViewControllerAnimated:YES];
3.跳转到指定的控制器(移除指定控制器上面的控制器)
[self.navigationController popToViewController:self.navigationController.childViewControllers[0] animated:YES];
3.在storyboard中操作以上设置
1.创建UIViewController
1.拖一个UINavigationController视图
2.拖一个UIViewController视图
3.将UIViewController设置为UINavigationController视图的rootViewController
按command+左键->拖线->选rootViewController
//注意:如果没设置view颜色,会显示为黑色
2.控制器的跳转
1.自动跳转
从原控制器的控件(能监听事件)中拖线到目标控制器->选show//push已废弃
2.手动跳转
从原控制器(上面的黄点)中拖线到目标控制器->选show//push已废弃
//返回只能用代码
//注意:在storyboard中线不能交叉
4.设置导航条的内容(哪个的导航条由哪个控制器设置)(在storyboard中找相对应属性)
1.设置导航条标题
self.navigationItem.title =@"标题";
2.设置导航条视图
self.navigationItem.titleView = [[UIView alloc]init];
3.设置导航条右边视图(左边同理)
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"right"style:0target:selfaction:@selector(rightClick)];
4.在导航条中设置自定义的控件
UIButton *btn = [[UIButton alloc]init];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:btn];
31.控制器之间数据传递
1.正向传递数据
在prepareForSegue方法中,先获取跳转时的segue,再获得目标控制器,再给目标控制器的属性赋值
//在storyboard中,不管是自动跳转还是手动跳转,都会调用这个方法
//用代码push不会调用
2.prepareForSegue底层实现:
1.创建segue对象
2.将self赋值给segue的sourceViewController(源控制器)
3.创建目标控制器,并赋值给segue的destinationViewController
4.传递参数
5.从源控制器push到目标控制器
3.逆向传递数据
1.导入头文件实现
//耦合性太强
2.使用代理
1.目标控制器
1.声明协议
2.声明代理属性(遵守协议)
3.调用代理方法//在返回上一层控制器前代用
2.源控制器
1.遵守协议
2.实现协议中的方法
3.设置self为目标控制器代理//在prepareForSegue中
3.使用block
1.目标控制器
1.声明block属性//一般使用typedef起别名
2.执行block//传递参数,在返回上层控制器之前执行
2.源控制器
1.获得目标控制器//在prepareForSegue中
2.给目标控制器的block赋值//即要执行的代码块
4.通知
1.目标控制器
发出通知到通知中心,并将数据打包成字典给userInfo//postNotification
2.源控制器
监听通知//注意:在dealloc中要移除监听
32.UITabBarController(底部导航条控制器)
1.代码创建
1.创建window
self.window = [[UIWindow alloc]init];
2.创建UITabBarController
UITabBarController *tabVC =[[UITabBarController alloc] init];
3.添加子控件
UIViewController *vc1 = [[UIViewController alloc] init];
[tabVC addChildViewController:vc1];
//添加多少个子控制器,则底部导航条平分为多少份,并创建按钮(默认无文字无颜色)
UIViewController *vc2 = [[UIViewController alloc] init];
[tabVC addChildViewController:vc2];
4.显示window
[self.window makeKeyAndVisible];
2.在storyboard中
1.拖一个UITabBarController视图
2.拖子控制器UIViewController
3.从UITabBarController拖线到UIViewController,选view controllers
4.重复第3步,可添加多个子控制器
3.设置导航条内容(哪个的导航条由哪个控制器设置)(在storyboard中找相对应属性)
1.设置显示文字
self.tabBarItem.title =@"消息";
2.设置右上角红色信息
self.tabBarItem.badgeValue =@"10";
3.设置显示图片
self.tabBarItem.image = [UIImage imageNamed:@"image"];
3.modal跳转控制器
1.代码跳转
1.跳转到指定控制器
UIViewController *vc = [UIViewController alloc] init];
[selfpresentViewController:vc animated:YEScompletion:^{ }];
2.返回上一层控制器
[selfdismissViewControllerAnimated:YEScompletion:^{ }];
2.在storyboard中
从源控制器(控件)拖线到目标控制器->选Present Modally//modal已废弃
//返回只能用代码实现
33.dismissed的原理:它本身就是一个消息机制首先会判断它有没有弹出控制器,假如有的话调用dismiss就会销毁弹出的控制假如没有的话就会销毁自己.
34.http:其0.9的版本和1.1的版本最大的区别是1.1可以持续链接他有两个操作一个是请求还有一个就是响应
35.get和post的区别
post发给服务器的参数放在请求体中其传递的数量没有限制它的安全性比get高一般包含敏感信息的文件都用post文件传输
get一般它的url长度不能超过1kb它传输的数据的大小一般都比较小
36.发送http请求的方案: nsurlConnection和nsurlsessioncfnetwork这三种
一般用第三方框架:AFNeWorking
37.将data转为字符串[[NSString alloc]initWithData:date encoding:NSUTF8StringEncoding];这种方式可以
38.http的
NSURLConnection的get请求的方式已被弃用
/*
//路径
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
//请求对象
NSURLRequest *quest = [NSURLRequest requestWithURL:url];
//异步请求的方式
[NSURLConnectionsendAsynchronousRequest:quest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
NSLog(@"%@ ",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}];
//同步请求的方式
NSURLResponse *response = [[NSURLResponse alloc]init];
NSData *date= [ NSURLConnectionsendSynchronousRequest:quest returningResponse:&response error:nil];
NSLog(@"%@ ",[[NSString alloc]initWithData:date encoding:NSUTF8StringEncoding]);
//代理的方式
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
//请求对象
NSURLRequest *quest = [NSURLRequest requestWithURL:url];
NSURLConnection *connect =[[NSURLConnectionalloc ]initWithRequest:quest delegate:self];
当有startImmediately且为NO的时候就要自动开启
[connect start];
*/
post的请求方式:
/*//1.确定请求路径
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520&pwd=520it&type=JSON"];
//2.创建请求对象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//3.创建会话对象
NSURLSession *session = [NSURLSession sharedSession];
//4.创建task
第一个参数:请求对象
第二个参数:completionHandler完成(成功|失败)后的回调
data:响应体
response:响应头信息
error:错误信息
//注意!!!completionHandler是在子线程中执行的
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//6.解析数据
NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
NSLog(@"%@",[NSThread currentThread]);
}];
//5.执行Task
[dataTask resume];*/
39.downloadtask下载任务:
1.传入url
2.新建请求对象
这里要设置假如程序退出了,下载从上次的地方接着开始下这时候就要用可变的请求去调用setValue的方法
3.创建session对象创建下载任务对象使用代理(遵守代理协议);
4.一定要resume恢复其操作;
调用方法: a.接受响应获取文件的总大小
新建一个输出流对象调用打开的方法用一个属性去接收
b.接收数据可以拿到当前的传输数据的大小总共传输了大小用一个属性去保存每次传输的大小再每次加上每次传输的数据的大小设置存储路径将数据一点点的加进磁盘内用输出流对象调用将数据写入磁盘内
并在这里调用刷新UI的方法在主线程中
c.任务完成或者请求出错
将输出流对象调用关闭的方法并将输出流对象设置成nil
[[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];本地文件的写入移动.
40.AFNetWorking的应用;
发送请求: get请求创建一个会话创建一个字典调用get方法
//NSString *url = @"http://120.25.226.186:32812/login";
AFHTTPSessionManager *http = [AFHTTPSessionManager manager];
NSDictionary *dic =@{
@"username":@"520it",
@"pwd":@"520it",
};
[http GET:@"http://120.25.226.186:32812/login"parameters:dic progress:nilsuccess:^(NSURLSessionDataTask *_Nonnulltask,id_NullableresponseObject) {
NSLog(@"请求成功");
NSLog(@"%@ ------%@",[responseObject class],responseObject);
} failure:^(NSURLSessionDataTask *_Nullabletask, NSError *_Nonnullerror) {
NSLog(@"请求失败");
}];
post请求创建一个会话创建一个字典调用post方法跟get方法一样;
2.文件上传upload
//1.创建会话管理者
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
//2.发送请求上传文件
/*
第一个参数:请求路径(NSString)
第二个参数:非文件参数
第三个参数:constructingBodyWithBlock拼接数据(告诉AFN要上传的数据是哪些)
第四个参数:progress进度回调
第五个参数:success成功回调
responseObject:响应体
第六个参数:failure失败的回调
*/
[manager POST:@"http://120.25.226.186:32812/upload"parameters:nilconstructingBodyWithBlock:^(id_NonnullformData) {
//拼接数据
/*
第一个参数:文件的路径(NSURL)
第二个参数:参数名~file
第三个参数:该文件上传到服务器以什么名称来保存
第四个参数:文件的二进制数据类型
*/
NSURL *url = [NSURL fileURLWithPath:@"/Users/apple/Desktop/Snip20160409_148.png"];
//[formData appendPartWithFileURL:url name:@"file" fileName:@"abc.png" mimeType:@"image/png" error:nil];
[formData appendPartWithFileURL:url name:@"file"error:nil];
} progress:^(NSProgress *_NonnulluploadProgress) {
NSLog(@"%f",1.0* uploadProgress.completedUnitCount / uploadProgress.totalUnitCount);
} success:^(NSURLSessionDataTask *_Nonnulltask,id_NullableresponseObject) {
NSLog(@"success--%@",responseObject);
} failure:^(NSURLSessionDataTask *_Nullabletask, NSError *_Nonnullerror) {
NSLog(@"failure -- %@",error);
}];
41.加密过程:机密的一些最基本的操作
NSString *key =@"abc";
NSString *string =@"520it";
//AES - ECB加密
/*
第一个参数:要加密的明文(字符串)
第二个参数:共享密钥
第三个参数:nil (初始向量)
*/
NSLog(@"AES - ECB加密:%@",[[EncryptionTools sharedEncryptionTools] encryptString:string keyString:key iv:nil]);
//FqRpCOQG9IL2QrKBHhM+fA==
NSLog(@"AES - ECB解密:%@",[[EncryptionTools sharedEncryptionTools] decryptString:@"FqRpCOQG9IL2QrKBHhM+fA=="keyString:key iv:nil]);
//AES -CBC
uint8_t iv[8] ={1,2,3,4,5,6,7,8};
NSData *data = [NSData dataWithBytes:iv length:sizeof(iv)];
NSLog(@"AES - CBC加密:%@",[[EncryptionTools sharedEncryptionTools] encryptString:string keyString:key iv:data]);
//$ echo -n "520it" |openssl enc -aes-128-cbc -K 616263 -nosalt -iv 0102030405060708 |base64
NSLog(@"AES - CBC解密:%@",[[EncryptionTools sharedEncryptionTools] decryptString:@"Kd9MN/rNEI40hdLhayPbUw=="keyString:key iv:data]);
//DES - ECB
//1.需要修改加密方式为kCCAlgorithmDES
[EncryptionTools sharedEncryptionTools].algorithm = kCCAlgorithmDES;
NSLog(@"DES - ECB加密:%@",[[EncryptionTools sharedEncryptionTools] encryptString:string keyString:key iv:nil]);
NSLog(@"DES - ECB解密:%@",[[EncryptionTools sharedEncryptionTools] decryptString:@"VqYjXo2ZlU4="keyString:key iv:nil]);
42.基础动画和核心动画
CAPropertyAnimation
是CAAnimation的子类,也是个抽象类,要想创建动画对象,应该使用它的两个子类:CABasicAnimation和CAKeyframeAnimation
属性解析:
keyPath:通过指定CALayer的一个属性名称为keyPath(NSString类型),并且对CALayer的这个属性的值进行修改,达到相应的动画效果。比如,指定@”position”为keyPath,就修改CALayer的position属性的值,以达到平移的动画效果
属性解析:(红色代表来自CAMediaTiming协议的属性)
duration:动画的持续时间
repeatCount:动画的重复次数
repeatDuration:动画的重复时间
removedOnCompletion:默认为YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards
fillMode:决定当前对象在非active时间段的行为.比如动画开始之前,动画结束之后
beginTime:可以用来设置动画延迟执行时间,若想延迟2s,就设置为CACurrentMediaTime()+2,CACurrentMediaTime()为图层的当前时间
timingFunction:速度控制函数,控制动画运行的节奏
delegate:动画代理
fromValue:keyPath相应属性的初始值
toValue:keyPath相应属性的结束值
随着动画的进行,在长度为duration的持续时间内,keyPath相应属性的值从fromValue渐渐地变为toValue
如果fillMode=kCAFillModeForwards和removedOnComletion=NO,那么在动画执行完毕后,图层会保持显示动画执行后的状态。但在实质上,图层的属性值还是动画执行前的初始值,并没有真正被改变。比如,CALayer的position初始值为(0,0),CABasicAnimation的fromValue为(10,10),toValue为(100,100),虽然动画执行完毕后图层保持在(100,100)这个位置,实质上图层的position还是为(0,0)
CAKeyframeAnimation是CApropertyAnimation的子类,跟CABasicAnimation的区别是:CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue),而CAKeyframeAnimation会使用一个NSArray保存这些数值
属性解析:
values:就是上述的NSArray对象。里面的元素称为”关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧
path:可以设置一个CGPathRef\CGMutablePathRef,让层跟着路径移动。path只对CALayer的anchorPoint和position起作用。如果你设置了path,那么values将被忽略
keyTimes:可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧.当keyTimes没有设置的时候,各个关键帧的时间是平分的
CABasicAnimation可看做是最多只有2个关键帧的CAKeyframeAnimation
运用:
CAAnimationGroup
CAAnimation的子类,可以保存一组动画对象,将CAAnimationGroup对象加入层后,组中所有动画对象可以同时并发运行
animations:用来保存一组动画对象的NSArray
默认情况下,一组动画对象是同时运行的,也可以通过设置动画对象的beginTime属性来更改动画的开始时间
组动画
CATransition是CAAnimation的子类,用于做转场动画,能够为层提供移出屏幕和移入屏幕的动画效果。iOS比Mac OS X的转场动画效果少一点
UINavigationController就是通过CATransition实现了将控制器的视图推入屏幕的动画效果
type:动画过渡类型
subtype:动画过渡方向
startProgress:动画起点(在整体动画的百分比)
endProgress:动画终点(在整体动画的百分比)
转场动画过渡效果
运用:
雨滴效果
补充:
一:CAAnimation——动画代理方法
1.CAAnimation在分类中定义了代理方法,是给NSObject添加的分类,所以任何对象,成为CAAnimation的代理都可以
@interfaceNSObject (CAAnimationDelegate)
/* Called when the animation begins its active duration. */
动画开始的时候调用:-(void)animationDidStart:(CAAnimation*)anim;
动画停止的时候调用:-(void)animationDidStop:(CAAnimation*)anim finished:(BOOL)flag;
@end
二:CALayer上动画的暂停和恢复
pragma mark暂停CALayer的动画
-(void)pauseLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
让CALayer的时间停止走动:layer.speed =0.0;
让CALayer的时间停留在pausedTime这个时刻:layer.timeOffset = pausedTime;
}
三:CALayer上动画的恢复
pragma mark恢复CALayer的动画
-(void)resumeLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = layer.timeOffset;
1.让CALayer的时间继续行走:layer.speed =1.0;
2.取消上次记录的停留时刻:layer.timeOffset =0.0;
3.取消上次设置的时间:layer.beginTime =0.0;
4.计算暂停的时间(这里也可以用CACurrentMediaTime()-pausedTime)
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime()fromLayer:nil] - pausedTime;
5.设置相对于父坐标系的开始时间(往后退timeSincePause):layer.beginTime = timeSincePause;
}
二、UIView动画
UIKit直接将动画集成到UIView类中,当内部的一些属性发生改变时,UIView将为这些改变提供动画支持
执行动画所需要的工作由UIView类自动完成,但仍要在希望执行动画时通知视图,为此需要将改变属性的代码放在[UIView beginAnimations:nilcontext:nil]和[UIView commitAnimations]之间
常见方法解析:
+ (void)setAnimationDelegate:(id)delegate
设置动画代理对象,当动画开始或者结束时会发消息给代理对象
+ (void)setAnimationWillStartSelector:(SEL)selector
当动画即将开始时,执行delegate对象的selector,并且把beginAnimations:context:中传入的参数传进selector
+ (void)setAnimationDidStopSelector:(SEL)selector
当动画结束时,执行delegate对象的selector,并且把beginAnimations:context:中传入的参数传进selector
+ (void)setAnimationDuration:(NSTimeInterval)duration
动画的持续时间,秒为单位
+ (void)setAnimationDelay:(NSTimeInterval)delay
动画延迟delay秒后再开始
+ (void)setAnimationStartDate:(NSDate *)startDate
动画的开始时间,默认为now
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve
动画的节奏控制,具体看下面的”备注”
+ (void)setAnimationRepeatCount:(float)repeatCount
动画的重复次数
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses
如果设置为YES,代表动画每次重复执行的效果会跟上一次相反
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition
forView:(UIView *)view cache:(BOOL)cache
设置视图view的过渡效果, transition指定过渡类型, cache设置YES代表使用视图缓存,性能较好
三、Block动画
Block
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void(^)(void))animations completion:(void(^)(BOOLfinished))completion
###参数解析:
duration:动画的持续时间
delay:动画延迟delay秒后开始
options:动画的节奏控制
animations:将改变视图属性的代码放在这个block中
completion:动画结束后,会自动调用这个block
+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void(^)(void))animations completion:(void(^)(BOOLfinished))completion
###参数解析:
duration:动画的持续时间
view:需要进行转场动画的视图
options:转场动画的类型
animations:将改变视图属性的代码放在这个block中
completion:动画结束后,会自动调用这个block
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void(^)(BOOLfinished))completion
###方法调用完毕后,相当于执行了下面两句代码:
//添加toView到父视图
[fromView.superview addSubview:toView];
//把fromView从父视图中移除
[fromView.superview removeFromSuperview];
###参数解析:
duration:动画的持续时间
options:转场动画的类型
animations:将改变视图属性的代码放在这个block中
completion:动画UIImageView的帧动画后,会自动调用这个block
UIImageView的帧动画
UIImageView可以让一系列的图片在特定的时间内按顺序显示
###相关属性解析:
animationImages:要显示的图片(一个装着UIImage的NSArray)
animationDuration:完整地显示一次animationImages中的所有图片所需的时间
animationRepeatCount:动画的执行次数(默认为0,代表无限循环)
###相关方法解析:
-(void)startAnimating;开始动画
-(void)stopAnimating;停止动画
-(BOOL)isAnimating;是否正在运行动画
UIActivityIndicatorView
###是一个旋转进度轮,可以用来告知用户有一个操作正在进行中,一般用initWithActivityIndicatorStyle初始化
###UIActivityIndicatorViewStyle有3个值可供选择:
UIActivityIndicatorViewStyleWhiteLarge//大型白色指示器
UIActivityIndicatorViewStyleWhite//标准尺寸白色指示器
UIActivityIndicatorViewStyleGray//灰色指示器,用于白色背景