当前位置: 首页 > 编程日记 > 正文

IOS 自定义相机, 使用 AVFoundation(附实现部分腾讯水印相机功能 demo)

原文链接:http://www.jianshu.com/p/c64bf543f16a
这是一款使用 AVFoundation 自定义的相机,与系统原生相机有一样的外观但比系统的相机更好、更符合实际的开发需要、可以自己修改 UI、实现拍照、取消、闪光灯控制、前后摄像头控制、聚焦、放大缩小、拍照后预览、重拍、使用照片、照片方向修正等功能、简洁易用,可以进行灵活的二次开发、可以用来开发类似腾讯水印相机等 app。 —— 由哈哈哈1484019331000分享

在项目中当我们遇到拍照的功能模块的时候,如果仅仅是用来拍照,系统提供的UIImagePickerController足够用来完成我们的任务。但是当我们的应用场景稍稍复杂点的时候,如要实现类似水印相机、美颜相机的时候,UIImagePickerController就有点力不从心了,需要自己去diy一个自定义相机。

UIImagePickerController使用起来比较简单易用,拍照,录制视频、控制闪光灯,前后摄像头的切换一应俱全。但是相机支持ui界面的自定义并不好(虽然可以支持自定义),在不同的系统下相机的功能界面还有所差别。

以水印相机为例,在水印相机中我们需要能够让水印模式实时的显示在相机的取景框中,而且水印模式还要可以左右滑动切换,在横屏的时候水印也要跟着横屏,还要有放大缩小镜头的以及点击屏幕能够聚焦等功能。


腾讯水印相机.gif

当然有人可能会想,将水印模式分成一个视图层然后放到相机的最上层不就行了吗?当然是不行的,首先UIImagePickerController在不同系统中的封装是略微不一样的,ui界面有所差别,界面不能够统一,即便是现在花了很过代码一个系统一个系统的适配,也很难保证以后不出问题,其次是手势的识别也有问题,即便是对手势进行了拦截处理,也不能解决,说白了也就是不是自己封装的东西,难以得到完美的掌控。

下面就开始自定义一个相机,并实现拍照、取消、闪光灯控制、前后摄像头控制、聚焦、放大缩小、拍照后预览、重拍、使用照片等功能。

@property (nonatomic, strong) ZTImagePickerOverLayView  *overlayView;//预览图层@property (nonatomic) dispatch_queue_t sessionQueue;@property (nonatomic, strong) AVCaptureSession* session;//用于捕捉视频和音频,协调视频和音频的输入和输出流@property (nonatomic, strong) AVCaptureDeviceInput* videoInput;@property (nonatomic, strong) AVCaptureStillImageOutput* stillImageOutput;//输出静态影像@property (nonatomic, strong) AVCaptureDevice             *device;//主要用来获取iphone一些关于相机设备的属性
@property (nonatomic, strong) AVCaptureVideoPreviewLayer* previewLayer;//预览图层layer

这里将相机的控件以及相机的实时显示的图层放在一个视图类ZTImagePickerOverLayView中,拍完照后的图层放在另外一个类ZTImagePickerPreImageView中,各个视图间的协调及部分逻辑放在控制器中ZTImagePickerController。封装完整个相机不过用了几百行代码。

1.初始化

 self.session = [[AVCaptureSession alloc] init];[self.session setSessionPreset:AVCaptureSessionPresetPhoto];NSError *error;self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];self.videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:self.device error:&error];self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];//输出设置。AVVideoCodecJPEG   输出jpeg格式图片NSDictionary * outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey, nil];[self.stillImageOutput setOutputSettings:outputSettings];if ([self.session canAddInput:self.videoInput]) {[self.session addInput:self.videoInput];}if ([self.session canAddOutput:self.stillImageOutput]) {[self.session addOutput:self.stillImageOutput];}//初始化预览图层self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];[self.previewLayer setVideoGravity:AVLayerVideoGravityResizeAspect];NSLog(@"%f",ScreenWidth);self.previewLayer.frame = CGRectMake(0, 0,ScreenWidth, ScreenHeight);self.preview = [[ZTImagePickerOverLayView alloc] init];self.preview.frame = CGRectMake(0, 0, ScreenWidth, ScreenHeight);[self.preview layoutSubviews];[self.preview.layer addSublayer:self.previewLayer];[self.view addSubview:self.preview];//添加顶部以及底部的自定义工具条[self.view addSubview:self.preview.topbar];[self.view addSubview:self.preview.buttomBar];self.preview.topbar.frame = CGRectMake(0, 0, self.view.width, 64 * ScreenWidth/320.0);self.preview.buttomBar.frame = CGRectMake(0, self.view.height - 70 * ScreenWidth/320.0 , self.view.width, 70* ScreenWidth/320.0);[self.preview layoutSubviews];//设置闪关灯模式if(self.device.isFlashAvailable)[self.preview setFlashModel:self.device.flashMode];else{self.preview.flashButton.hidden = YES;self.preview.cameraSwitchButton.hidden = YES;}//设置拍照后预览图层self.preImageView = [[ZTImagePickerPreImageView alloc] initWithFrame:CGRectMake(0, 0, ScreenWidth, ScreenHeight)];[self.preImageView layoutSubviews];self.preImageView.hidden = YES;[self.view addSubview:self.preImageView];

2.添加手势给预览层添加捏合手势控制放大缩小,添加点击手势来聚焦

 UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:selfaction:@selector(handlePinchGesture:)];pinch.delegate = self;[self.preview addGestureRecognizer:pinch];UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:selfaction:@selector(focusAction:)];[self.preview addGestureRecognizer:tap];

3.给控件添加响应事件闪光灯打开、关闭、自动,摄像头切换、取消、拍照、重新拍照、使用照片等按钮添加响应事件

[self.preview.cameraSwitchButton addTarget:self action:@selector(switchCameraSegmentedControlClick:) forControlEvents:UIControlEventTouchUpInside];[self.preview.flashAutoButton addTarget:self action:@selector(flashButtonClick:) forControlEvents:UIControlEventTouchUpInside];[self.preview.flashOpeanButton addTarget:self action:@selector(flashButtonClick:) forControlEvents:UIControlEventTouchUpInside];[self.preview.flashCloseButton addTarget:self action:@selector(flashButtonClick:) forControlEvents:UIControlEventTouchUpInside];[self.preview.takePictureButton addTarget:self action:@selector(takePhotoButtonClick:) forControlEvents:UIControlEventTouchUpInside];[self.preview.cancelButton addTarget:self action:@selector(cancelButtonClick:) forControlEvents:UIControlEventTouchUpInside];[self.preImageView.reTakeButton addTarget:self action:@selector(retakeButtonClick:) forControlEvents:UIControlEventTouchUpInside];[self.preImageView.useImageButton addTarget:self action:@selector(useImageButtonClick:) forControlEvents:UIControlEventTouchUpInside];

4.闪光灯控制

- (void)flashButtonClick:(UIButton *)sender {//[self.preview reSetTopbar];[self.preview chosedFlashButton:sender];NSLog(@"flashButtonClick");AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];//修改前必须先锁定[device lockForConfiguration:nil];//必须判定是否有闪光灯,否则如果没有闪光灯会崩溃if ([device hasFlash]) {if([sender.titleLabel.text isEqualToString:@"打开"]){if([device isFlashModeSupported:AVCaptureFlashModeOn])[device setFlashMode:AVCaptureFlashModeOn];}else if ([sender.titleLabel.text isEqualToString:@"自动"]){if([device isFlashModeSupported:AVCaptureFlashModeAuto])[device setFlashMode:AVCaptureFlashModeAuto];}else if ([sender.titleLabel.text isEqualToString:@"关闭"]){if([device isFlashModeSupported:AVCaptureFlashModeOff])[device setFlashMode:AVCaptureFlashModeOff];}} else {NSLog(@"设备不支持闪光灯");}[device unlockForConfiguration];
}

5.前后摄像头切换

- (void)switchCameraSegmentedControlClick:(id)sender {//NSLog(@"%ld",(long)sender.selectedSegmentIndex);AVCaptureDevicePosition desiredPosition;AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];if (isUsingFrontFacingCamera){if(device.isFlashAvailable) self.preview.flashButton.hidden = NO;desiredPosition = AVCaptureDevicePositionBack;}else{desiredPosition = AVCaptureDevicePositionFront;[self.preview reSetTopbar];self.preview.flashButton.hidden = YES;}for (AVCaptureDevice *d in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {if ([d position] == desiredPosition) {[self.previewLayer.session beginConfiguration];AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:d error:nil];for (AVCaptureInput *oldInput in self.previewLayer.session.inputs) {[[self.previewLayer session] removeInput:oldInput];}[self.previewLayer.session addInput:input];[self.previewLayer.session commitConfiguration];break;}}isUsingFrontFacingCamera = !isUsingFrontFacingCamera;
}

6.拍照

- (void)takePhotoButtonClick:(id )sender{AVCaptureConnection *stillImageConnection = [self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo];UIDeviceOrientation curDeviceOrientation = [[UIDevice currentDevice] orientation];AVCaptureVideoOrientation avcaptureOrientation = [self avOrientationForDeviceOrientation:curDeviceOrientation];[stillImageConnection setVideoOrientation:avcaptureOrientation];[stillImageConnection setVideoScaleAndCropFactor:self.effectiveScale];[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:stillImageConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];self.imageData = jpegData;CFDictionaryRef attachments = CMCopyDictionaryOfAttachments(kCFAllocatorDefault,imageDataSampleBuffer,kCMAttachmentMode_ShouldPropagate);UIImage *image = [UIImage imageWithData:jpegData];[self waterMarkFixed];self.preImageView.imageView.image = image;[self.preview hiddenSelfAndBars:YES];self.preImageView.hidden = NO;ALAuthorizationStatus author = [ALAssetsLibrary authorizationStatus];if (author == ALAuthorizationStatusRestricted || author ==ALAuthorizationStatusDenied){//无权限return ;}//保存到相册
//            ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
//            [library writeImageDataToSavedPhotosAlbum:jpegData metadata:(__bridge id)attachments completionBlock:^(NSURL *assetURL, NSError *error) {
//        
//            }];}];if([self.delegate respondsToSelector:@selector(imagePickerControllerTakePhoto:)])[self.delegate imagePickerControllerTakePhoto:self];}

7.放大缩小

- (void)handlePinchGesture:(UIPinchGestureRecognizer *)recognizer{BOOL allTouchesAreOnThePreviewLayer = YES;NSUInteger numTouches = [recognizer numberOfTouches], i;for ( i = 0; i < numTouches; ++i ) {CGPoint location = [recognizer locationOfTouch:i inView:self.preview];CGPoint convertedLocation = [self.previewLayer convertPoint:location fromLayer:self.previewLayer.superlayer];if ( ! [self.previewLayer containsPoint:convertedLocation] ) {allTouchesAreOnThePreviewLayer = NO;break;}}if ( allTouchesAreOnThePreviewLayer ) {self.effectiveScale = self.beginGestureScale * recognizer.scale;if (self.effectiveScale < 1.0){self.effectiveScale = 1.0;}CGFloat maxScaleAndCropFactor = [[self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo] videoMaxScaleAndCropFactor];if (self.effectiveScale > maxScaleAndCropFactor)self.effectiveScale = maxScaleAndCropFactor;[CATransaction begin];[CATransaction setAnimationDuration:.025];[self.previewLayer setAffineTransform:CGAffineTransformMakeScale(self.effectiveScale, self.effectiveScale)];[CATransaction commit];}
}

8.照片方向修正拍完照的时候,拍出的照片你会发现呈现的方向不对,需要对照片的方向进行修正。

 AVCaptureVideoOrientation avcaptureOrientation = [self avOrientationForDeviceOrientation:curDeviceOrientation];[stillImageConnection setVideoOrientation:avcaptureOrientation];- (AVCaptureVideoOrientation)avOrientationForDeviceOrientation:(UIDeviceOrientation)deviceOrientation
{AVCaptureVideoOrientation result = (AVCaptureVideoOrientation)deviceOrientation;if ( deviceOrientation == UIDeviceOrientationLandscapeLeft )result = AVCaptureVideoOrientationLandscapeRight;else if ( deviceOrientation == UIDeviceOrientationLandscapeRight )result = AVCaptureVideoOrientationLandscapeLeft;return result;
}

这里需要注意的是如果想要拍完照的效果和UIimagePickerController的效果一样,即在横屏下拍完照,照片要旋转显示并且显示的小一些,那么就要对拍完照预览图层进行修改。

图片

在预览图层中修改imageview的大小。(这部分代码我并没有加到demo中,如果想实现拍完照后照片的方向与系统相机的一样,可以在ZTImagePickerPreImageView中加上)

- (void)changeImageViewFrameIfNeeded:(UIDeviceOrientation)orientation{if(orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight){self.imageView.frame = CGRectMake(0, 0, self.width, 240 * [UIScreen mainScreen].bounds.size.width / 320.0);self.imageView.centerY = self.height / 2.0;}else{_imageView.frame = CGRectMake(0, 0, self.width, 418 * [UIScreen mainScreen].bounds.size.width / 320.0);_imageView.centerY = self.height / 2.0;}
}

仅仅是这样还不够,还要对设备方向的获取进行改进。通常我们获取设备方向是通过[[UIDevice currentDevice] orientation] 或者通过[UIApplication sharedApplication].statusBarOrientation的方式来获取。但这两种方式有一个缺点,在竖排方向开关关闭的时候,获取到的方向是正确的,在开关打开的时候获取到的方向是竖直方向,在横屏等情况下获取的方向不正确。这时候就要通过CMMotionManager来获取方向了。(下面这段代码也没有加到demo中,如果有这样的功能需求,可以在ZTImagePickerController中加上这段代码)

- (void)p_startMotionManager{self.deviceOrientation = UIDeviceOrientationPortrait;if (_motionManager == nil) {_motionManager = [[CMMotionManager alloc] init];}_motionManager.deviceMotionUpdateInterval = 1/15.0;if (_motionManager.deviceMotionAvailable) {NSLog(@"Device Motion Available");[_motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue]withHandler: ^(CMDeviceMotion *motion, NSError *error){[self performSelectorOnMainThread:@selector(handleDeviceMotion:) withObject:motion waitUntilDone:YES];}];} else {NSLog(@"No device motion on device.");}
}- (void)p_stopMonotionManager{[_motionManager stopDeviceMotionUpdates];_motionManager = nil;
}

二、添加水印如果要实现类似腾讯的水印相机形式的水印,需要对水印专门做一个图层来进行管理。将水印图层放在相机的最上层就可以实时看到水印了,并且可以左右切换水印。这里使用scrollview来容纳每种水印样式,如果水印样式比较多当然可以使用collectionView来容纳。

为了让水印图层的手势(scrollView的左右滑动,每种水印样式视图中的控件响应手势)响应不与相机图层的手势响应不冲突,在水印图层可以将手势进行拦截,根据实际情况来返回响应手势的视图控件。

这里的代码根据实际情况修改
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{UIView *view = [super hitTest:point withEvent:event];CGPoint tempPoint = [self.reportView convertPoint:point fromView:self];if(CGRectContainsPoint(self.reportView.reportTypeLb.frame, tempPoint)){view = self.reportView.reportTypeLb;return view;}NSInteger left = 0,top = 0, height = 0,width = self.contentSize.width;height = MAX(self.reportView.xmNameLb.top, self.handleProblemView.userLb.top);if([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft){left = self.height - height;width = self.width;}if(CGRectContainsPoint(CGRectMake(left, top, width, height), point)){view = [self.superview.subviews objectAtIndex:0];view = [view hitTest:point withEvent:event];}else{}return view;
}

拍完照选择好水印样式后,将水印样式用的空间绘制到照片上,就形成了水印照片

- (UIImage *)markedImageWithType:(XBWaterMark )waterMarkType date:(NSDate *)date user:(NSString *)user placLocation:(ZTLocationModel *)locationModel withPhone:(NSString *)phone xmType:(NSString *)xmType{if (self.size.width == 0.0 || self.size.height == 0.0) return nil;UIImage *defaultImage = nil;CGFloat scale = [UIScreen mainScreen].scale;if(scale >= 3) scale = 2;UIImage *image = [self thumbnailForMaxWidth:1024/scale maxHeight:1024/scale];CGSize newSize = CGSizeMake(image.size.width*image.scale/scale, image.size.height*image.scale/scale);UIView *waterMarkView = [self p_markWaterMarkView:waterMarkType date:date user:userplacLocation:locationModel  withPhone:phone newSize:newSize xmType:xmType];//将水印样式中的控件绘制到图片UIGraphicsBeginImageContextWithOptions(newSize, YES, 0.0);CGContextRef context = UIGraphicsGetCurrentContext();CGContextSaveGState(context);[image drawInRect:CGRectMake(0.0, 0.0, newSize.width, newSize.height)];for (UIView *view in waterMarkView.subviews) {if([view isKindOfClass:[UIImageView class]]){UIImageView *iv = (UIImageView *)view;[iv.image drawInRect:CGRectMake(iv.left,iv.top, iv.width, iv.height)];}else if ([view isKindOfClass:[UILabel class]]){UILabel *lb = (UILabel *)view;UIImage *lbImage = [lb imageByRenderingView];[lbImage drawInRect:CGRectMake(lb.left, lb.top, lb.width, lb.height)];}}CGContextRestoreGState(context);defaultImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();return defaultImage;
}

效果图


自定义水印相机.gif

自定义相机demo


相关文章:

如何成为一个好的测试工程师(转载,大意)

对于测试功能是的两个不同观点&#xff1a;软实力和技术能力。 个人觉得技术能力80%可以被大众掌握&#xff0c;但是软实力是需要花费很多时间去培养和塑造的。一下几点也是能够衡量个人技能的一些标准&#xff1a; 1&#xff0c;沟通技能-口头和书面能力 与人的第一印象&#…

ubuntu下7z文件的解压方法

apt-get install p7zip-full 控制台会打出以下信息&#xff1a; 正在读取软件包列表... 完成正在分析软件包的依赖关系树 正在读取状态信息... 完成 建议安装的软件包&#xff1a; p7zip-rar下列【新】软件包将被安装&#xff1a; p7zip-full升级了 0 个软件包&…

Docker的使用(一:Docker入门程序)

1、编写Dockerfile文件&#xff1b; 注&#xff1a;创建一个空的Docker工作目录dockerspace&#xff0c;进而进入该目录&#xff0c;并创建编写dockerfile文件&#xff1b; 2、编写外部文件。 注&#xff1a;在当前目录&#xff08;dockerspace&#xff09;下分别创建require…

iOS OpenCV 图像灰度处理

2017-06-21 小溪彼岸 Cocoa开发者社区推荐人&#xff1a;wo709128079 有时候开发过程中&#xff0c;切图满足不了我们的需求&#xff0c;此时我们需要对图像进行灰度处理&#xff0c;例如QQ头像在线、离线等不同状态等。 可以尝试的解决方案&#xff1a; 第一种&#xff1a;让U…

【VS开发】【电子电路技术】RJ45以太网传输线研究

RJ45以太网传输线研究 最近研究远距离差分视频传输方案&#xff0c;理所当然想到了LVDS协议。至于选用cameralink传输线&#xff0c;还是选用其他方案&#xff0c;本人更倾向于廉价的RJ45以太网线来实现LVDS差分信号的传输。 由于RJ45网线内部为4对双绞线&#xff0c;至于以太网…

Wiz开发 定时器的使用与处理

这只是一些代码片段&#xff0c;由于Wiz开发的资料实在不多&#xff0c;而且内容都不够新。这里的代码主要参考Tools.Timer这个插件&#xff0c;但是由于内部实现的很多变化&#xff0c;Tools.Timer这个插件基本上已经无法使用了。定时器的注册与删除 使用定时器&#xff0c;是…

Docker的使用(二:Docker客户端常用指令练习)

1、列出镜像&#xff1b; 2、搜索镜像&#xff1b; 3、拉取镜像&#xff1b; 4、构建镜像&#xff1b; 4.1、在Dockerfile文件所在目录构建镜像&#xff1b; 4.2、在其他目录构建镜像&#xff1b; 4.3、查看镜像是否构建成功&#xff1b; 5、删除镜像&#xff1b; 6、创建并启…

实现简书个人中心UI效果

这两天比较闲&#xff0c;简单实现了一下个人中心页面scrollView嵌套的效果&#xff0c;也就是下边这个页面,大家感受一下先&#xff1a; JSDemo2.gif 首先讲下实现思路&#xff0c;很多人看到这个界面觉得是多个scrollView嵌套实现的&#xff0c;其实苹果不推荐scrollView的嵌…

PHPCMSv9首页显示分页点击下一页跳转链接出现错误,跳转到后台的解决方案

1 引用页写为 {pc:content action"lists" catid"10" order"updatetime DESC" thumb"0" num"1" page"$_GET[page]"}{loop $data $v}....{/loop}{$pages} {/pc}2 phpcms/libs/functions/global.func.php文件 get_…

顺序查找和二分查找

{线性的顺序查找}function seqSearch(sArr: array of Integer;aCount: Integer;const index: Integer):Integer;var i: Integer;begin Result : -1; for i : 0 to aCount do if sArr[i]index then begin Result : i; Break; end;end;{对数性的二分查找}f…

Docker的使用(三:Docker Hub远程镜像管理)

1、登录 Docker Hub&#xff1b; 2、修改镜像名称&#xff1b; 3、登录认证&#xff1b; 4、推送镜像&#xff1b; 5、查看验证&#xff1b;

啊里大鱼短信发送API

https://api.alidayu.com/doc2/apiDetail?spm0.0.0.0.SEe3dm&apiId25450 转载于:https://www.cnblogs.com/shiningrise/p/5626708.html

GCD API

&#xff08;可直接复制到Xcode中查看&#xff09; /***********************************************************************************************************************************##目录##知识点&#xff1a;GCD中有2个核心概念&#xff1a;任务和队列任务&#…

查看Linux系统中某目录的大小

命令&#xff1a;du -sh 目录名来查看&#xff0c;如下 du -sh /root 命令显示结果为&#xff1a;1.2M /root 检查是否有分区使用率use&#xff05;过高&#xff0c;如发现某个分区空间接近用完&#xff0c;可以进入该分区的挂载点&#xff0c;用以下命令找出占用空间最多的文件…

Docker的使用(四:Docker Registry本地私有仓库搭建知识点总结)

任务一&#xff1a; Docker Registry本地私有仓库搭建 1、启动Docker Registry&#xff1b; 2、重命名镜像&#xff1b; 3、推送镜像&#xff1b; 4、浏览器查看验证&#xff1b; 5、文件查看验证&#xff1b; 任务二&#xff1a;Docker Registry本地私有仓库配置&#xff1b;…

iOS多线程全套:线程生命周期,多线程的四种解决方案,线程安全问题,GCD的使用,NSOperation的使用(上)

2017-07-08 remember17 Cocoa开发者社区目的 本文主要是分享iOS多线程的相关内容&#xff0c;为了更系统的讲解&#xff0c;将分为以下7个方面来展开描述。 多线程的基本概念 线程的状态与生命周期 多线程的四种解决方案&#xff1a;pthread&#xff0c;NSThread&#xff…

C基础知识小总结(十)

"如有不正确之处&#xff0c;请指出&#xff0c;谢谢" --Mood <指针和函数> 指针函数 函数指针 <最基本的使用函数指针> < 函数指针做为形参 > <字符指针> <字符数组> < 返回局部变量指针 > < 结构体指针> 指向结构体变…

支付方式(2)——支付宝集成及使用

每一个支付平台都有自己的加密、解密的原理&#xff1b;还有各种签名的原理&#xff1b;通过各种内容发送数据&#xff0c;防止恶意攻击等功能的原理。 接下来对于部署支付方式&#xff0c;首先要分清几个名词&#xff1a; 集成接入&#xff1a;支付宝已经集成好各种原理和函数…

Kali Linux攻防系统(一:攻防系统Kali Linux下载安装与更新)

任务一&#xff1a;攻防系统Kali Linux下载安装与更新 1.1、安装Kali Linux虚拟机 1.1.1、电脑硬件配置至少达到 CPU 内存 存储 >四核 >4G >20G 1.1.2、VMware Workstations版本为14及以上&#xff1b; 1.1.3、虚拟机系统版本选择Debian 8.X或者Ubuntu&#x…

iOS多线程全套:线程生命周期,多线程的四种解决方案,线程安全问题,GCD的使用,NSOperation的使用(下)

2017-07-08 remember17 Cocoa开发者社区7NSOperation的理解与使用 No.1&#xff1a;NSOperation简介 NSOperation是基于GCD之上的更高一层封装&#xff0c;NSOperation需要配合NSOperationQueue来实现多线程。 NSOperation实现多线程的步骤如下&#xff1a; 1. 创建任务&#x…

linux网卡绑定脚本

2013-08-20 15:30:51 此脚本适用于CentOS5.x和CentOS6.x。 #!/bin/bash #******************************************** # Copyright (c) Beijing DaoWoo Times Technology Co., Ltd. 2011 # # Author : Wu XuLei (wuxuleidaowoo.com) # FILE : bonding.sh …

EBS 抓trace 文件

如果要对FORM的操作做TRACE操作&#xff0c;可以使用 帮助->诊断->跟踪 中启用跟踪功能来实现。 但是如果要实现对并发请求的trace&#xff0c;需要在 系统管理员->并发->方案->定义 里找到对应的并发请求&#xff0c;并勾选”启用跟踪”项。然后提交这个并发请…

Kali Linux攻防系统(三:在Kali Linux系统中配置安全测试浏览器及系统清理备份)

任务三&#xff1a;配置安全测试浏览器及系统清理备份 3.1、汉化Firefox并安装安全插件 3.1.1、汉化Firefox浏览器&#xff0c;安装中文插件&#xff0c;并更改设置&#xff1b; 3.1.2、在浏览器附加组件管理器中查找“Web Developr”插件 3.1.3、安装添加附件组件 3.2、手动…

一篇文章学懂Shell脚本

Shell脚本,就是利用Shell的命令解释的功能&#xff0c;对一个纯文本的文件进行解析&#xff0c;然后执行这些功能&#xff0c;也可以说Shell脚本就是一系列命令的集合。 Shell可以直接使用在win/Unix/Linux上面&#xff0c;并且可以调用大量系统内部的功能来解释执行程序&#…

OC系列foundation Kit基础-NSDate

一.获取当前时间 1.1创建一个日期对象 NSDate *date [NSDate date];NSLog("%",date);输出结果&#xff1a; 2016-07-01 17:31:02.410 OCString[907:402963] 2016-07-01 09:31:02 0000 //因为时区不一样&#xff0c;需要格式化为本地时间 Program ended with exit…

sql server 中将由逗号“,”分割的一个字符串,转换为一个表,并应用与 in 条件...

select * from tablenmae where id in(1,2,3) 这样的语句和常用&#xff0c;但是如果in 后面的 1&#xff0c;2&#xff0c;3是变量怎么办呢&#xff0c;一般会用字符串连接的方式构造sql语句 string aa"1,2,3";string sqltxt"select * from tablename where id…

Nmap安装和扫描(一:Nmap安装和扫描基础知识点总结)

实验目的及要求 完成VMware Workstations14平台安装&#xff0c;会应用相关操作&#xff1b;完成Windows 7操作系统及Kali Linux操作系统的安装&#xff1b;掌握安全扫描的概念、意义及应用分析&#xff1b;掌握Nmap扫描器的安装&#xff1b;针对特定扫描目的&#xff0c;掌握…

最新最全的 Android 开源项目合集(一)

原文链接&#xff1a;https://github.com/opendigg/awesome-github-android-ui 抽屉菜单 MaterialDrawer ★7337 - 安卓抽屉效果实现方案 Side-Menu.Android ★3865 - 创意边侧菜单 FlowingDrawer ★1744 - 向右滑动流动抽屉效果 SlidingRootNav ★1338 - 仿DrawerLayout的View…

dotNet core Windows上 部署

转载于:https://www.cnblogs.com/yiyanwannian/p/5637896.html

HDU 1061 Rightmost Digit

解题报告&#xff1a;1097的翻版&#xff0c;求 N^N 次方的个位是多少&#xff1f; 详见我的另一篇HDU 1097 A hard puzzle稍加修改就行 1 #include<cstdio>2 int main( ) {3 int xh[20],n,a,N,T;4 scanf("%d",&T);5 while(T--) {6 sc…