1. iOS音视频相关

参考文档:

参考代码: VideoEditing

@property (weak, nonatomic)  IBOutlet UIView            *viewContainer;
@property (weak, nonatomic)  IBOutlet UIImageView       *centerImageView;
@property (strong,nonatomic) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer; //相机拍摄预览图层

- (void)viewWillAppear:(BOOL)animated {
  ...

  /* 创建视频预览层,用于实时展示摄像头状态 */
  _captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.captureSession];

  CALayer *layer = self.viewContainer.layer;
  
  /* 将视频预览层添加到界面中 */
  //[layer addSublayer:_captureVideoPreviewLayer];
  [layer insertSublayer:_captureVideoPreviewLayer below:self.centerImageView.layer];
  
  ...
}

2. UIGestureRecognizer(手势操作)

点击:

UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc]
                                         initWithTarget:self action:@selector(action:)];
imageView.userInteractionEnabled = YES;
[imageView addGestureRecognizer:tapRecognizer];

-(void) action:(id)sender {
  UITapGestureRecognizer *tapRecognizer = (UITapGestureRecognizer *)sender;
  // tapRecognizer.view ...
}

长按:

{
  ...
  let longPressRecognizer:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLandmarkImageLongPress(_:)))
  someUIView!.addGestureRecognizer(longPressRecognizer)
  ...
}

func handleLandmarkImageLongPress(longPressRecognizer:UILongPressGestureRecognizer) {
  if ((UIGestureRecognizerState.Ended == longPressRecognizer.state)
    || (UIGestureRecognizerState.Cancelled == longPressRecognizer.state)
    || (UIGestureRecognizerState.Failed == longPressRecognizer.state)) {
    ...
    return
  }
  
  let someUIView = longPressRecognizer.view as! SomeUIView
  let point:CGPoint = longPressRecognizer.locationInView(someUIView)
  ...

  if (UIGestureRecognizerState.Began == longPressRecognizer.state) {
    ...
  }
}

捏:

{
  let pinchRecognizer:UIPinchGestureRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(handleLandmarkImagePinch(_:)))
  someUIView!.addGestureRecognizer(pinchRecognizer)
}

func handleLandmarkImagePinch(pinchRecognizer:UIPinchGestureRecognizer) {
    if (UIGestureRecognizerState.Began == pinchRecognizer.state) {
      ...
      return
    }
    
    if (UIGestureRecognizerState.Changed == pinchRecognizer.state) {
      ...
      let scale: CGFloat = pinchRecognizer.scale;
      ...
      return
    }
    
    if ((UIGestureRecognizerState.Ended == pinchRecognizer.state)
      || (UIGestureRecognizerState.Cancelled == pinchRecognizer.state)) {
      ...
      return
    }
  }

参考文档:

3. 网络编程

文件上传(多文件):

#define kUrl @"http://192.168.1.208/FileUpload.aspx"
#define kBOUNDARY_STRING @"lsclone"

#pragma mark 取得mime types
-(NSString *)getMIMETypes:(NSString *)fileName{
    return @"image/jpg";
}

#pragma mark 取得数据体
-(NSData *)getHttpBody:(NSString *)fileName{
    NSMutableData *dataM=[NSMutableData data];
    NSString *strTop=[NSString stringWithFormat:@"--%@\nContent-Disposition: form-data; name=\"images\"; filename=\"%@\"\nContent-Type: %@\n\n",kBOUNDARY_STRING,fileName,[self getMIMETypes:fileName]];
    NSString *strBottom = [NSString stringWithFormat:@"\n"];
    NSString *filePath=[[NSBundle mainBundle] pathForResource:fileName ofType:nil];
    NSData *fileData=[NSData dataWithContentsOfFile:filePath];
    [dataM appendData:[strTop dataUsingEncoding:NSUTF8StringEncoding]];
    [dataM appendData:fileData];
    [dataM appendData:[strBottom dataUsingEncoding:NSUTF8StringEncoding]];
    return dataM;
}

#pragma mark 上传文件
-(void)uploadFile:(NSArray*)nameArray {
    NSURL *url = [NSURL URLWithString:kUrl];
    NSMutableURLRequest *request= [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:5.0f];
    
    request.HTTPMethod=@"POST";
    
    NSMutableData *data = [NSMutableData data];
    for(int i=0; i<[nameArray count]; i++) {
        [data appendData:[self getHttpBody:(NSString*)nameArray[i]]];
    }
    NSString *strBottom = [NSString stringWithFormat:@"--%@--", kBOUNDARY_STRING];
    [data appendData:[strBottom dataUsingEncoding:NSUTF8StringEncoding]];
    
    //通过请求头设置
    [request setValue:[NSString stringWithFormat:@"%lu",(unsigned long)data.length] forHTTPHeaderField:@"Content-Length"];
    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",kBOUNDARY_STRING] forHTTPHeaderField:@"Content-Type"];
    
    //设置数据体
    request.HTTPBody=data;

    //发送异步请求
    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        if(connectionError){
            NSLog(@"error:%@", connectionError.localizedDescription);
        } else {
            NSError *jsonError = nil;
            id jsonObj = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
            if(jsonObj == nil) {
                NSLog(@"Error parsing JSON: %@", jsonError);
            } else {
                if ([jsonObj isKindOfClass:[NSArray class]]) {
                    NSArray *jsonArray = (NSArray *)jsonObj;
                    ...
                } else if([jsonObj isKindOfClass:[NSDictionary class]]) {
                    NSDictionary *jsonDictionary = (NSDictionary *)jsonObj;
                    ...
                }
            }
        }
    }];
}

*参考文档:

4. 多线程

参考文档: iOS多线程编程:线程同步总结

5. 自动布局

参考文档:

6. UIImageView

  //添加边框  
  CALayer *layer = [imageView layer];  
  layer.borderColor = [UIColor whiteColor].CGColor;  
  layer.borderWidth = 5.0f;  
  //添加四个边阴影  
  imageView.layer.shadowColor = [UIColor blackColor].CGColor;  
  imageView.layer.shadowOffset = CGSizeMake(0,0);  
  imageView.layer.shadowOpacity = 0.5;  
  imageView.layer.shadowRadius = 10.0;//给imageview添加阴影和边框  
  //添加两个边的阴影  
  imageView.layer.shadowColor = [UIColor blackColor].CGColor;  
  imageView.layer.shadowOffset = CGSizeMake(4,4);  
  imageView.layer.shadowOpacity = 0.5;  
  imageView.layer.shadowRadius=2.0;  

参考网址: IOS-UIImageView

7. UIScrollView

#define ItemWidth   100
#define ItemHeight  80
#define ItemMargin  2
#define ItemNums    10

for(int i=0, pos=0; i<ItemNums; i++) {
    UIImageView* imageview = [[UIImageView alloc]initWithFrame:CGRectMake(pos, 0, ItemWidth, ItemHeight)];
    imageview.userInteractionEnabled = YES;
    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(selectItem:)];
    [imageview addGestureRecognizer:singleTap];
    
    pos += ItemWidth+ItemMargin;
    [self.scrollView setContentSize:CGSizeMake(pos, ItemHeight)];
    [self.scrollView addSubview:imageview];
}

参考网址:

8. 十六进制颜色值转UIColor

/*
**  hexColorString:
**  0xffffff or #FFFFFF
 */
+ (UIColor *)colorWithHexString:(NSString *)hexColorString {  
    if ([hexColorString length] < 6) { //长度不合法  
        return [UIColor blackColor];  
    }  
    NSString *tempString = [hexColorString lowercaseString];  
    if ([tempString hasPrefix:@"0x"]) { //检查开头是0x  
        tempString = [tempString substringFromIndex:2];  
    } else if ([tempString hasPrefix:@"#"]) { //检查开头是#  
        tempString = [tempString substringFromIndex:1];  
    }  
    if ([tempString length] != 6) {  
        return [UIColor blackColor];  
    }  
    //分解三种颜色的值  
    NSRange range = NSMakeRange(0, 2);  
    NSString *rString = [tempString substringWithRange:range];  
    range.location = 2;  
    NSString *gString = [tempString substringWithRange:range];  
    range.location = 4;  
    NSString *bString = [tempString substringWithRange:range];  
    //取三种颜色值  
    unsigned int r, g, b;  
    [[NSScanner scannerWithString:rString] scanHexInt:&r];  
    [[NSScanner scannerWithString:gString] scanHexInt:&g];  
    [[NSScanner scannerWithString:bString] scanHexInt:&b];  
    return [UIColor colorWithRed:((float)r / 255.0f)  
                           green:((float)g / 255.0f)  
                            blue:((float)b / 255.0f)  
                           alpha:1.0f];  
} 

9. 获取视频方向

+ (NSUInteger)degressFromVideoFileWithURL:(NSURL *)url {
  //根据url创建AVURLAsset
  AVURLAsset *urlAsset = [AVURLAsset assetWithURL:url];
  
  //check video orientation
  UIImageOrientation orient = UIImageOrientationUp;
  NSArray *tracks = [urlAsset tracksWithMediaType:AVMediaTypeVideo];
  if([tracks count] > 0) {
      AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
      CGAffineTransform t = videoTrack.preferredTransform;
      if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0){
          // AVCaptureVideoOrientationPortrait
          orient = UIImageOrientationRight;  // rotate 90 degrees clockwise
      }else if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0){
          // AVCaptureVideoOrientationPortraitUpsideDown
          orient = UIImageOrientationLeft;   // rotate 90 degrees counter clockwise
      }else if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0){
          // AVCaptureVideoOrientationLandscapeRight
          orient = UIImageOrientationUp;     // rotate 0 degrees clockwise
      }else if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0){
          // AVCaptureVideoOrientationLandscapeLeft
          orient = UIImageOrientationDown;   // rotate 180 degrees
      }
  }
}

参考网址: 获取视频方向

10. UISlider

CGRect frame = CGRectMake(0.0, 219.0, 323.0, 20.0);
UISlider *myslider = [[UISlider alloc] initWithFrame:frame];

[myslider addTarget:self action:@selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
[myslider setBackgroundColor:[UIColor clearColor]];
[myslider setThumbImage: [UIImage imageNamed:@"sliderThumb@2x.png"] forState:UIControlStateNormal];

myslider.minimumValue = 0.0;
myslider.maximumValue = 50.0;
myslider.continuous = YES;
myslider.value = 15.0;
[self.view addSubview:myslider];

11. UINavigationController

实现方式1:

利用Storyboard创建Navigation Control,可以自定义root view control。

二级导航添加方法:创建second view control,按住ctrl键,点击root view上的button或prototype cell,并向second view拖拽。
弹出storyboard sagues, 选择push(push,modal, custom)。

参考网址: Use Storyboards to Build Navigation Controller and Table View

实现方式2:

利用Storyboard创建Navigation Control,可以自定义root view control。

二级导航添加方法:Windows+N创建second view control并添加到storyboard,右键second view control,点击push并拖动到root view control,弹出manual并确认,建立导航push segue to "second view control";root view control.m添加button点击响应函数:

- (IBAction)buttonClicked:(id)sender {
    //SndViewController *sndCtrl = [self.storyboard instantiateViewControllerWithIdentifier:@"sndpage"];
    SndViewController* sndCtrl = [[SndViewController alloc] init];
    
    // push data to second view control
    ...
    
    [self.navigationController pushViewController:sndCtrl animated:YES];
}

参考网址:

另注:

12. UINavigationController.navigationBar

/* change tint color */
self.navigationController.navigationBar.tintColor = [UIColor redColor];
/* change title color */
self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName:[UIColor redColor]};
/* set navigationbar background to transparent (alpha 0) */
[[[self.navigationController.navigationBar subviews] objectAtIndex:0] setAlpha:0];

参考网址:

13. Image Orientation

参考网址:

14. CGContext

UIGraphicsBeginImageContext(CGSizeMake(100, 100));

/* draw image */
[srcimage drawAtPoint:CGPointMake(0,0)];

CGContextRef ctx = UIGraphicsGetCurrentContext();

/* draw point */
CGContextSetFillColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextAddEllipseInRect(ctx, CGRectMake(x, y, width, height));
CGContextFillPath(ctx);

/* draw line */
CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextMoveToPoint(ctx, x1, y1);
CGContextAddLineToPoint(ctx, x2, y2);
CGContextSetLineWidth(ctx, 10);
CGContextStrokePath(ctx);

/* get target image */
UIImage* dstimage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

参考网址:

15. Quartz 2D编程(CGContext)

/* CGContextDrawImage draws image upside down */

UIImage *image = [UIImage imageNamed:@"testImage.png"];    
CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height);       

CGContextTranslateCTM(context, 0, image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

CGContextDrawImage(context, imageRect, image.CGImage);

参考网址:

16. UIView transform属性

 //实现的是放大和缩小
    view.transform=CGAffineTransformScale(view.transform, 0.5, 0.5);  

 //实现的是旋转
    view.transform=CGAffineTransformRotate(view.transform, 0.2);

 //实现的是平移
    view.transform=CGAffineTransformTranslate(view.transform, 20, 20);

参考: UIView的transform属性以及 CGAffineTransform的使用

17. 访问本地相册

#import <MobileCoreServices/MobileCoreServices.h>

@interface ViewController()<UINavigationControllerDelegate, UIImagePickerControllerDelegate>
@end

@implementation ViewController
- (IBAction)buttonClicked:(UIButton *)sender {
  UIImagePickerController *picker = [[UIImagePickerController alloc] init];
  
  picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
  picker.mediaTypes = @[(NSString*)kUTTypeImage, (NSString *)kUTTypeMovie, (NSString*)kUTTypeVideo];
  picker.delegate = self;
  picker.allowsEditing = YES; //设置选择后的图片/视频可被编辑
  
  [self presentViewController:picker animated:YES completion:nil]; //打开相册
}

#pragma mark - UIImagePickerControllerDelegate方法
-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
  NSString *type = [info objectForKey:UIImagePickerControllerMediaType];
  if ([type isEqualToString:@"public.image"]) {
    UIImage* image = [info objectForKey:UIImagePickerControllerOriginalImage]; //图片
    ...
  } else if ([type isEqualToString:@"public.movie"] || [type isEqualToString:@"public.video"]) {
    NSURL* url = [info objectForKey:UIImagePickerControllerMediaURL]; //视频路径
    ...
  }
  [self dismissViewControllerAnimated:YES completion:nil]; //关闭相册
}
@end

参考网址:

18. UIView触摸事件处理

public func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
public func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?)
public func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?)
public func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?)

参考: iOS Programming – 触摸事件处理

19. UIView Animation

objective-c code:

- (void)moveSideBarToXposition: (int) iXposition{

    [UIView animateWithDuration:0.5f
                          delay:0.1
                        options: UIViewAnimationOptionTransitionNone
                     animations:^{  self.mainView.frame = CGRectMake(iXposition, 20, self.mainView.frame.size.width, self.mainView.frame.size.height); }

                     completion:^(BOOL finished){
                         if (self.isSidebarHidden==YES) {
                             self.isSidebarHidden = NO;
                         }

                         else{
                             self.isSidebarHidden = YES;
                         }
                     }];
}

swift code:

func moveSideBarToXposition(iXposition: Float) {
    let convertedXposition = CGFloat(iXposition)
    UIView.animateWithDuration(0.5, delay: 1.0, options: UIViewAnimationOptions.TransitionNone, animations: { () -> Void in

        self.contentView.frame = CGRectMake(convertedXposition, 20, self.contentView.frame.size.width, self.contentView.frame.size.height)

        }, completion: { (finished: Bool) -> Void in

            // you can do this in a shorter, more concise way by setting the value to its opposite, NOT value
            isMenuHidden = !isMenuHidden
    })
}

参考网址:

20. Key-Value Observing机制(KVO)

override func viewWillAppear(animated: Bool) {
  captureMovieFileOutput?.addObserver(self, forKeyPath: "recording", options: NSKeyValueObservingOptions([.Old, .New]), context: nil)
}

deinit {
  captureMovieFileOutput?.removeObserver(self, forKeyPath: "recording")
}

var progressTimer: NSTimer?

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
  guard captureMovieFileOutput != nil else {
    return
  }
  if keyPath == "recording" {
    if !self.captureMovieFileOutput!.recording {
      self.progressTimer?.invalidate()
      self.progressTimer = nil
    } else {
      if (self.progressTimer == nil) {
        self.progressTimer = NSTimer.createTimer(0.005, block: {
          let duration: Float64 = CMTimeGetSeconds(self.captureMovieFileOutput!.recordedDuration)
          let time: Float64 = CMTimeGetSeconds(self.captureMovieFileOutput!.maxRecordedDuration)
          let progress: Float = Float(duration/time)
          self.recordProgressView.setProgress(progress, animated: true)
          }, repeats: true)
        NSRunLoop.mainRunLoop().addTimer(progressTimer!, forMode: NSDefaultRunLoopMode)
      }
    }
  }
}
import UIKit

public typealias TimerClosure = @convention(block)()->()

extension NSTimer {
  class func createTimer(timeInterval:NSTimeInterval, block:TimerClosure, repeats:Bool) -> NSTimer {
    return NSTimer.init(timeInterval: timeInterval, target: self, selector: #selector(NSTimer.invoke), userInfo: unsafeBitCast(block, AnyObject.self), repeats: true)
  }
  
  class func invoke(timer:NSTimer) {
    let block = unsafeBitCast(timer.userInfo, TimerClosure.self)
    block()
  }
}

参考网址:

21. Quartz 2D transform matrix

应用(swift version):

class MyView: UIView {
  ...
  
  //Location transformation is necessary because of zooming in or out.
  func transformLocation(location location:CGPoint) -> CGPoint {
    let transformedLocation = CGPointMake(location.x * transform.a + location.y * transform.c + transform.tx,
                                          location.x * transform.b + location.y * transform.d + transform.ty)
    
    return transformedLocation
  }
  
  func transformLocation(touch:UITouch) -> CGPoint {
    let location = touch.locationInView(self)
    return transformLocation(location: location)
  }
  
  override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if 1 != touches.count {
      return
    }
    let touch:UITouch = touches.first!
    let location:CGPoint = transformLocation(touch)
    ...
  }
}

touch.locationInView(self) 获取的是相对UIView原始尺寸的坐标(x, y),UIView缩放之后的相应坐标点需要通过transformLocation计算,参考The Math Behind the Matrices

22. Table View

参考网址:

23. Using Assets

参考网址: assets官网

24. Convert NSDate to NSString

参考网址:

25. NSData

1. write NSData to file

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    // Generate the file path
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"yourfilename.dat"];

     // Save NSData into file system
    [data writeToFile:dataPath atomically:YES];
});

2. NSMutableData remove bytes

参考网址: NSMutableData remove bytes

26.1 BLE(蓝牙)

参考网址:

26.2 External Accessories(外部设备)

参考网址: iOS MFi App端开发步骤

27. multi-thread and NSRunLoop

RunLoop从字面上看是运行循环的意思,首先循环体的开始需要检测是否有需要处理的事件,如果有则去处理,如果没有则进入睡眠以节省CPU时间。 所以重点便是这个需要处理的事件,在RunLoop中,需要处理的事件分两类,一种是输入源,一种是定时器。

每一个线程都有其对应的RunLoop,但是默认非主线程的RunLoop是没有运行的,需要为RunLoop添加至少一个事件源,然后去run它。一般情况下我们是没有必要去启用线程的RunLoop的,除非你在一个单独的线程中需要长久的检测某个事件。

参考网址:

start sub-thread and runloop:

{
  // NSThread *_thread
  _thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadFunc) object:nil];
  [_thread start];
}

- (void)threadFunc {
  NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:time target:self selector:@selector(onTimer) userInfo:nil repeats:YES];
  [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
  [[NSRunLoop currentRunLoop] run];
}

- (void)onTimer {
}

re-write for making runloop can be stopped

- (void)threadFunc {

  [NSStream setDelegate:self];
  [NSStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
                      forMode:NSDefaultRunLoopMode];
  [NSStream open];
  
  _shouldKeepRunning = YES;
  while (_shouldKeepRunning && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                                        beforeDate:[NSDate distantFuture]]);
  
  // TODO: some operation after stopping runloop
}

#pragma mark NSStreamDelegate
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
}

- (void)close {
  [self performSelector:@selector(stop:) onThread:_thread withObject:nil waitUntilDone:NO];
}

- (void)stop:(id)sender {

    [NSStream close];
    [NSStream removeFromRunLoop:[NSRunLoop currentRunLoop]
                        forMode:NSDefaultRunLoopMode];
    [NSStream setDelegate:nil];
    
    _shouldKeepRunning = NO;
}

参考网址: