每日更新关注:http://weibo.com/hanjunqiang 新浪微博!手机加iOS开发者交流QQ群: 446310206
1.iOS - 推送 openssl合并//1.1 生成 opensslkey openssl pkcs12 -nocerts -out PushKey.pem -in apns-dev-cert.p12 //1.2 输入以上成功之后会出现以下这段: Enter PEM pass phrase:输入密码 //2.导出 pem openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12 //3.将 key 和 pem 合并 cat PushKey.pem apns-dev-cert.pem > apns-Dev.pem===========================================================================================================
2.Cookie(小甜饼)
//cookie介绍
Cookie由服务器端生成,发送给客户端
客户端将Cookie的key/value保存到某个目录下的文本文件内
如果客户端支持Cookie,下次请求同一网站时就可以Cookie直接发送给服务器
Cookie名称和值由服务器端开发自己定义
Cookies最典型的应用是判定注册用户是否已经登录,记录用户登录信息,简化下次登录的过程
另一个重要应用场合是“购物车”
在iOS程序中,默认就支持Cookie,程序员无需做任何处理
如果服务器返回Cookie,会自动保存在沙盒的 Library/Cookies 目录中
/* Cookie的存储策略 */
/* Cookie的保存 */
保存在 沙盒/Library/Cookies 目录下,以二进制的形式保存
但是仍然能够看到密码的明文,说明不安全!
/* 获取cookie的方法 */
/* Cookie的缺陷 */
Cookie会被附加在每个HTTP请求中,会增加额外的流量
在HTTP请求中的Cookie是明文传递的,因此会有安全隐患,除非使用HTTPS
@property NSHTTPCookieAcceptPolicy cookieAcceptPolicy; NSHTTPCookieAcceptPolicyAlways, 永远 NSHTTPCookieAcceptPolicyNever, 永不 NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain 只记录主域名的Cookie //提示:如果禁用Cookie有些网络访问会不正常! //这个选项只要知道即可,不建议修改!
/* Cookie的保存 */
保存在 沙盒/Library/Cookies 目录下,以二进制的形式保存
但是仍然能够看到密码的明文,说明不安全!
/* 获取cookie的方法 */
// 检查Cookie中是否保存了用户的信息 // 1. 拿出所有的cookie NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]; // 2. 遍历cookies检查是否有用户名和密码 for (NSHTTPCookie *cookie in cookies) { /** NSHTTPCookie中存储的内容 name: 变量名->变量名&值是从服务器返回的 value: 变量值 */ NSLog(@"%@", cookie); if ([cookie.name isEqualToString:@"userName"]) { // 用户名 self.nameText.text = cookie.value; } else if ([cookie.name isEqualToString:@"userPassword"]) { // 密码 self.pwdText.text = cookie.value; } } // 3. 删除Cookie // 读取所有cookie NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]; // 删除cookie for (NSHTTPCookie *cookie in cookies) { [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie]; }
/* Cookie的缺陷 */
Cookie会被附加在每个HTTP请求中,会增加额外的流量
在HTTP请求中的Cookie是明文传递的,因此会有安全隐患,除非使用HTTPS
Cookie的大小限制在4KB左右,不适合存储复杂的数据信息
===========================================================================================================
3.截图使用场景: iOS 7中的代码代段
// 使用上下文截图,并使用指定的区域裁剪,模板代码 - (void)screenShot { // 将要被截图的view,即窗口的根控制器的view(必须不含状态栏,默认ios7中控制器是包含了状态栏的) BeyondViewController *beyondVC = self.view.window.rootViewController; // 背景图片 总的大小 CGSize size = beyondVC.view.frame.size; // 开启上下文,使用参数之后,截出来的是原图(YES 0.0 质量高) UIGraphicsBeginImageContextWithOptions(size, YES, 0.0); // 裁剪的关键代码,要裁剪的矩形范围 CGRect rect = CGRectMake(0, -20, size.width, size.height + 20 ); //注:iOS7以后renderInContext:由drawViewHierarchyInRect:afterScreenUpdates:替代 [beyondVC.view drawViewHierarchyInRect:rect afterScreenUpdates:NO]; // 从上下文中,取出UIImage UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext(); // 添加截取好的图片到图片数组 [_cutImages addObject:snapshot]; // 千万记得,结束上下文(移除栈顶上下文) UIGraphicsEndImageContext(); }
===========================================================================================================
4.解决UIButton 按钮重复点击
配合Github上我写的扩展使用,简单实用:
https://github.com/XiaoHanGe/JQButtonRepeatClick
配合Github上我写的扩展使用,简单实用:
https://github.com/XiaoHanGe/JQButtonRepeatClick
// test UIButton *testBtn = [UIButton buttonWithType:UIButtonTypeCustom]; testBtn.frame = CGRectMake(100, 100, [UIScreen mainScreen].bounds.size.width-200, [UIScreen mainScreen].bounds.size.height/3); testBtn.backgroundColor = [UIColor greenColor]; [testBtn setTitleColor:[UIColor redColor] forState:(UIControlStateNormal)]; [testBtn setTitle:@"测试" forState:UIControlStateNormal]; [testBtn addTarget:self action:@selector(goToTestAction:) forControlEvents:UIControlEventTouchUpInside]; // 设置几秒内忽略重复点击 testBtn.JQ_acceptEventInterval = 1; [self.view addSubview:testBtn];
每日更新关注:http://weibo.com/hanjunqiang 新浪微博!手机加iOS开发者交流QQ群: 446310206
===========================================================================================================
5.#pragma mark -- 设置在一个文本中所有特殊字符的特殊颜色
===========================================================================================================
6.放大缩小
===========================================================================================================
===========================================================================================================
10.优化建议
===========================================================================================================
===========================================================================================================
12.tabBar的隐藏与消失
===========================================================================================================
+ (NSMutableAttributedString *)setAllText:(NSString *)allStr andSpcifiStr:(NSString *)specifiStr withColor:(UIColor *)color specifiStrFont:(UIFont *)font { NSMutableAttributedString *mutableAttributedStr = [[NSMutableAttributedString alloc] initWithString:allStr]; if (color == nil) { color = [UIColor redColor]; } if (font == nil) { font = [UIFont systemFontOfSize:17.]; } // NSArray *array = [allStr componentsSeparatedByString:specifiStr];//array.cout-1是所有字符特殊字符出现的次数 NSRange searchRange = NSMakeRange(0, [allStr length]); NSRange range; //拿到所有的相同字符的range while ((range = [allStr rangeOfString:specifiStr options:0 range:searchRange]).location != NSNotFound) { //改变多次搜索时searchRange的位置 searchRange = NSMakeRange(NSMaxRange(range), [allStr length] - NSMaxRange(range)); //设置富文本 [mutableAttributedStr addAttribute:NSForegroundColorAttributeName value:color range:range]; [mutableAttributedStr addAttribute:NSFontAttributeName value:font range:range]; } return mutableAttributedStr; }
===========================================================================================================
6.放大缩小
// 放大 - (void)shakeToShow:(UIButton*)aView{ CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; animation.duration = 0.5; NSMutableArray *values = [NSMutableArray array]; [values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.1, 0.1, 1.0)]]; [values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.2, 1.2, 1.0)]]; [values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.9, 0.9, 1.0)]]; [values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 1.0)]]; animation.values = values; [aView.layer addAnimation:animation forKey:nil]; } // 缩小 - (void)shakeToHidden:(UIButton*)aView{ CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; animation.duration = 0.5; NSMutableArray *values = [NSMutableArray array]; [values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 1.0)]]; [values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.9, 0.9, 1.0)]]; [values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.2, 1.2, 1.0)]]; [values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.1, 0.1, 1.0)]]; animation.values = values; [aView.layer addAnimation:animation forKey:nil]; } - (void)showWithAView:(UIButton*)aView { [CATransaction begin]; { // start the transform animation from its current value if it's already running NSValue *fromValue = [aView.layer animationForKey:@"transform"] ? [aView.layer.presentationLayer valueForKey:@"transform"] : [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.5, 0.5, 1)]; CABasicAnimation *scaleAnim = [CABasicAnimation animationWithKeyPath:@"transform"]; scaleAnim.fromValue = fromValue; scaleAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; [scaleAnim setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:0.8 :2.5 :0.35 :0.5]]; scaleAnim.removedOnCompletion = NO; scaleAnim.fillMode = kCAFillModeForwards; scaleAnim.duration = 0.4; [aView.layer addAnimation:scaleAnim forKey:@"transform"]; CABasicAnimation* fadeInAnim = [CABasicAnimation animationWithKeyPath:@"opacity"]; fadeInAnim.fromValue = [aView.layer.presentationLayer valueForKey:@"opacity"]; fadeInAnim.duration = 0.1; fadeInAnim.toValue = @1.0; [aView.layer addAnimation:fadeInAnim forKey:@"opacity"]; aView.layer.opacity = 1.0; } [CATransaction commit]; } - (void)hideWithAView:(UIButton*)aView { [CATransaction begin]; { [CATransaction setCompletionBlock:^{ // remove the transform animation if the animation finished and wasn't interrupted if (aView.layer.opacity == 0.0) [aView.layer removeAnimationForKey:@"transform"]; }]; CABasicAnimation *scaleAnim = [CABasicAnimation animationWithKeyPath:@"transform"]; scaleAnim.fromValue = [aView.layer.presentationLayer valueForKey:@"transform"]; scaleAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.5, 0.5, 1)]; scaleAnim.duration = 0.6; scaleAnim.removedOnCompletion = NO; scaleAnim.fillMode = kCAFillModeForwards; [scaleAnim setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:0.1 :-2 :0.3 :3]]; [aView.layer addAnimation:scaleAnim forKey:@"transform"]; CABasicAnimation* fadeOutAnim = [CABasicAnimation animationWithKeyPath:@"opacity"]; fadeOutAnim.fromValue = [aView.layer.presentationLayer valueForKey:@"opacity"]; fadeOutAnim.toValue = @0.0; fadeOutAnim.duration = 0.8; [aView.layer addAnimation:fadeOutAnim forKey:@"opacity"]; aView.layer.opacity = 0.0; } [CATransaction commit]; }
===========================================================================================================
7.#pragma mark - 抖动动画
===========================================================================================================
- (void)shakeAnimation { CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position.x"]; //获取当前View的position坐标 CGFloat positionX = self.layer.position.x; //设置抖动的范围 animation.values = @[@(positionX-10),@(positionX),@(positionX+10)]; //动画重复的次数 animation.repeatCount = 3; //动画时间 animation.duration = 0.07; //设置自动反转 animation.autoreverses = YES; [self.layer addAnimation:animation forKey:nil]; }
===========================================================================================================
8.iOS - 直接退出应用
===========================================================================================================
//使用 -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ [self exitApplication]; } //退出方法 - (void)exitApp { [UIView beginAnimations:@"exitApplication" context:nil]; [UIView setAnimationDuration:0.5]; [UIView setAnimationDelegate:self]; [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self.view.window cache:NO]; [UIView setAnimationDidStopSelector:@selector(animationFinished:finished:context:)]; self.view.window.bounds = CGRectMake(0, 0, 0, 0); [UIView commitAnimations]; } - (void)animationFinished:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context { if ([animationID compare:@"exitApplication"] == 0) { //退出 exit(0); } }
===========================================================================================================
9.iOS - 图片模糊效果
vImage 方式添加通用模糊效果 #import <Accelerate/Accelerate.h> //加模糊效果,image是图片,blur是模糊度 - (UIImage *)blurryImage:(UIImage *)image withBlurLevel:(CGFloat)blur { if (image==nil) { NSLog(@"error:为图片添加模糊效果时,未能获取原始图片"); return nil; } //模糊度, if ((blur < 0.1f) || (blur > 2.0f)) { blur = 0.5f; } //boxSize必须大于0 int boxSize = (int)(blur * 100); boxSize -= (boxSize % 2) + 1; NSLog(@"boxSize:%i",boxSize); //图像处理 CGImageRef img = image.CGImage; //需要引入#import <Accelerate/Accelerate.h> /* This document describes the Accelerate Framework, which contains C APIs for vector and matrix math, digital signal processing, large number handling, and image processing. 本文档介绍了Accelerate Framework,其中包含C语言应用程序接口(API)的向量和矩阵数学,数字信号处理,大量处理和图像处理。 */ //图像缓存,输入缓存,输出缓存 vImage_Buffer inBuffer, outBuffer; vImage_Error error; //像素缓存 void *pixelBuffer; //数据源提供者,Defines an opaque type that supplies Quartz with data. CGDataProviderRef inProvider = CGImageGetDataProvider(img); // provider’s data. CFDataRef inBitmapData = CGDataProviderCopyData(inProvider); //宽,高,字节/行,data inBuffer.width = CGImageGetWidth(img); inBuffer.height = CGImageGetHeight(img); inBuffer.rowBytes = CGImageGetBytesPerRow(img); inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData); //像数缓存,字节行*图片高 pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img)); outBuffer.data = pixelBuffer; outBuffer.width = CGImageGetWidth(img); outBuffer.height = CGImageGetHeight(img); outBuffer.rowBytes = CGImageGetBytesPerRow(img); // 第三个中间的缓存区,抗锯齿的效果 void *pixelBuffer2 = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img)); vImage_Buffer outBuffer2; outBuffer2.data = pixelBuffer2; outBuffer2.width = CGImageGetWidth(img); outBuffer2.height = CGImageGetHeight(img); outBuffer2.rowBytes = CGImageGetBytesPerRow(img); //Convolves a region of interest within an ARGB8888 source image by an implicit M x N kernel that has the effect of a box filter. error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer2, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend); error = vImageBoxConvolve_ARGB8888(&outBuffer2, &inBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend); error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend); if (error) { NSLog(@"error from convolution %ld", error); } // NSLog(@"字节组成部分:%zu",CGImageGetBitsPerComponent(img)); //颜色空间DeviceRGB CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); //用图片创建上下文,CGImageGetBitsPerComponent(img),7,8 CGContextRef ctx = CGBitmapContextCreate( outBuffer.data, outBuffer.width, outBuffer.height, 8, outBuffer.rowBytes, colorSpace, CGImageGetBitmapInfo(image.CGImage)); //根据上下文,处理过的图片,重新组件 CGImageRef imageRef = CGBitmapContextCreateImage (ctx); UIImage *returnImage = [UIImage imageWithCGImage:imageRef]; //clean up CGContextRelease(ctx); CGColorSpaceRelease(colorSpace); free(pixelBuffer); free(pixelBuffer2); CFRelease(inBitmapData); //CGColorSpaceRelease(colorSpace); //多余的释放 CGImageRelease(imageRef); return returnImage; }
===========================================================================================================
10.优化建议
优化建议:
避免图层混合
· 确保控件的opaque属性设置为true,确保backgroundColor和父视图颜色一致且不透明
· 如无特殊需要,不要设置低于1的alpha值
· 确保UIImage没有alpha通道
避免临时转换
· 确保图片大小和frame一致,不要在滑动时缩放图片
· 确保图片颜色格式被GPU支持,避免劳烦CPU转换
慎用离屏渲染
· 绝大多数时候离屏渲染会影响性能
· 重写drawRect方法,设置圆角、阴影、模糊效果,光栅化都会导致离屏渲染
· 设置阴影效果是加上阴影路径
· 确保控件的opaque属性设置为true,确保backgroundColor和父视图颜色一致且不透明
· 如无特殊需要,不要设置低于1的alpha值
· 确保UIImage没有alpha通道
避免临时转换
· 确保图片大小和frame一致,不要在滑动时缩放图片
· 确保图片颜色格式被GPU支持,避免劳烦CPU转换
慎用离屏渲染
· 绝大多数时候离屏渲染会影响性能
· 重写drawRect方法,设置圆角、阴影、模糊效果,光栅化都会导致离屏渲染
· 设置阴影效果是加上阴影路径
· 滑动时若需要圆角效果,开启光栅化
===========================================================================================================
11.iOS - 收起键盘
对应控件 resignFirstResponder
touchesBegin 中 [self.view endEditing:YES]; [[UIApplication sharedApplication]sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil]; [[[UIApplication sharedApplication]keyWindow]endEditing:YES];
===========================================================================================================
12.tabBar的隐藏与消失
// tabBar的隐藏与消失 - (void)hidesTabBar:(BOOL)hidden{ [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0]; for (UIView *view in self.tabBarController.view.subviews){ if ([view isKindOfClass:[UITabBar class]]) { if (hidden) { [view setFrame:CGRectMake(view.frame.origin.x, [UIScreen mainScreen].bounds.size.height, view.frame.size.width , view.frame.size.height)]; }else{ [view setFrame:CGRectMake(view.frame.origin.x, [UIScreen mainScreen].bounds.size.height - 49, view.frame.size.width, view.frame.size.height)]; } }else{ if([view isKindOfClass:NSClassFromString(@"UITransitionView")]){ if (hidden){ [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, [UIScreen mainScreen].bounds.size.height)]; }else{ [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, [UIScreen mainScreen].bounds.size.height - 49 )]; } } } } [UIView commitAnimations]; }
===========================================================================================================
13.判断页面消失或出现时是push还是pop操作:
- (void)viewWillDisappear:(BOOL)animated { NSArray *viewControllers = self.navigationController.viewControllers;//获取当前的视图控制其 if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) { //当前视图控制器在栈中,故为push操作 NSLog(@"push"); } else if ([viewControllers indexOfObject:self] == NSNotFound) { //当前视图控制器不在栈中,故为pop操作 NSLog(@"pop"); } }