美文网首页
iOS 开发记录

iOS 开发记录

作者: 玉米包谷 | 来源:发表于2017-03-11 17:53 被阅读89次

    打印方法名

    NSLog(@"%s",__FUNCTION__);
    NSLog(@"%@",NSStringFromSelector(_cmd));
    

    类、方法判断

    // 用于判断是否包含某个类方法
    respondsToSelector:(SEL)                      
    
    conformsToProtocol:(Protocol *)          
     // 判定某个类     
    isKindOfClass:(__unsafe_unretained Class)    
    
    isMemberOfClass:(__unsafe_unretained Class)   
    
    // 获取某个类的类名字符串
    NSStringFromClass([UITextView class]);
    
    // 通过字符串获取某个类
    NSClassFromString(@"UITextView");
    

    emoji表情转换

    // 表情转UTF8
    [contentstringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    
    // UTF8转表情
    [content stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    

    数组和字典与NSData互转

    NSArray * arr1 = [[NSArray alloc]initWithObjects:@"0",@"5",nil];
    
    // NSArray->NSData(转字典也使用该方法)
    NSData  * data = [NSKeyedArchiver archivedDataWithRootObject:arr1];
    
    // NSData->NSArray(转字典也使用该方法)
    NSArray * arr2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    

    字典、JSON互转

    // json格式字符串转字典:
    + (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString
    {
        if (jsonString == nil) {
            return nil;
        }
    
        NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
        NSError *err;
        NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];
    
        if(err) {
            NSLog(@"json解析失败:%@",err);
            return nil;
        }
        return dic;
    }
    
    // 字典转json格式字符串:
    + (NSString*)dictionaryToJson:(NSDictionary *)dic
    {
        NSError *parseError = nil;
        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&parseError];
        return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    

    自定义结构体(类似于CGSizeMake)

    /**
     *  分页
     */
    struct LBPage{
        NSInteger page;
        NSInteger number;
    };
    typedef struct LBPage LBPage;
    
    /**
     *  创建分页结构体
     */
    CG_INLINE LBPage
    LBPageMake(NSInteger page, NSInteger number)
    {
      LBPage p;
      p.page = page; 
      p.number = number; 
      return p;
    }
    

    实现多选参数(如UIAlertView初始化)

    // 定义方法:
    - (void)buttonTitles:(nullable NSString *)titles,...;
    
    // 实现方法
    - (void)buttonTitles:(nullableNSString *)titles,...{
      NSString *other = nil;
      va_list args; //用于指向第一个参数
      NSMutableArray *fruits = [NSMutableArray array];
      if(titles){
        [fruits addObject:titles];
        // 对args进行初始化,让它指向可变参数表里面的第一个参数
        va_start(args, titles);
        // 获取指定类型的值
        while((other = va_arg(args, NSString*))){
          [fruits addObject:other];
        }
        va_end(args);//将args关闭
      }
      NSLog(@"%@", fruits);
    }
    
    // 方法调用
    [self buttonTitles:@“1”,@“2”,nil];
    

    判断当前设备是模拟器还是真机

    #if TARGET_IPHONE_SIMULATOR // 模拟器
    #define SIMULATOR_TEST 0
    #else
    #define SIMULATOR_TEST 1
    #endif
    

    调试打印

    #ifdef DEBUG
      #define DLog(fmt, ...) NSLog((@"<%s : %d> %s  " fmt), [[[NSString stringWithUTF8String:__FILE__] lastPathComponent]   UTF8String], __LINE__, __PRETTY_FUNCTION__,  ##__VA_ARGS__);
      #define NSLog(FORMAT, ...) fprintf(stderr,"%s:%d\t%s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
    #else
      #define DLog(...) /* */
      #define NSLog(FORMAT, ...) nil
    #endif
    

    枚举定义

    typedef NS_ENUM(NSInteger,YMDatePickerMode){
        YMDatePickerModeTime,
        YMDatePickerModeDate,
        YMDatePickerDateAndTime,
        YMDatePickerModeCountDownTimer
    };
    
    typedef enum {
        YMDateUnitYear,
        YMDateUnitMonth,
        YMDateUnitDay
    }YMDateUnit;
    

    统音量控制(通过UISlider直接控制系统音量)

    // 导入头文件
    #import <MediaPlayer/MediaPlayer.h> 
    
    // 控制系统音量只需要对slider进行控制即可控制
    MPVolumeView *volumeView = [[MPVolumeView alloc] init];
    [volumeView sizeToFit];
    NSLog(@"%@",volumeView.subviews);
    
    // 将系统的音量调整视图赋给自定义的UISlider,实现拖动自定义UISlider直接改变系统音量
    UISlider * slider = [[UISlider alloc]init];
    slider.backgroundColor = [UIColor blueColor];
    for (UIControl *view in volumeView.subviews) {
         if ([view.superclass isSubclassOfClass:[UISlider class]]) {
         slider = (UISlider *)view;
         }
    }
    
    slider.autoresizesSubviews = NO;
    slider.autoresizingMask = UIViewAutoresizingNone;
    slider.hidden = YES;
    NSLog(@"_backVolumeView.value = %lf",_backVolumeView.value);
    

    获取系统音量

    #import <AVFoundation/AVFoundation.h> 监听系统音量
    
    // 创建监听
    NSError *error;
    [[AVAudioSession sharedInstance] setActive:YES error:&error];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(volumeChanged:)
                                                 name:@"AVSystemController_SystemVolumeDidChangeNotification"
                                               object:nil];
    
    // 开始接收远程控制事件
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    
    // 结束接收远程控制事件
    [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
    
    // 获取音量
    - (void)volumeChanged:(NSNotification *)notification
    {
         NSLog(@"volume = %@",notification.userInfo);
    }
    

    截取当前屏幕

    // currentView 当前的view  创建一个基于位图的图形上下文并指定大小为
    UIGraphicsBeginImageContext(self.view.bounds.size);
    
    // renderInContext呈现接受者及其子范围到指定的上下文
    [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    
    // 返回一个基于当前图形上下文的图片
    _currentScreen = UIGraphicsGetImageFromCurrentImageContext();
    
    // 移除栈顶的基于当前位图的图形上下文
    UIGraphicsEndImageContext();
    
    // 然后将该图片保存到图片图
    UIImageWriteToSavedPhotosAlbum(_currentScreen, nil, nil, nil);
    

    截取视频帧图片

    - (void)thumbnailImageForVideo:(NSString *)videoPath atTime:(NSTimeInterval)time success:(void(^)(UIImage *image))success
    {
        dispatch_queue_t   globQueue =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(globQueue, ^{
            // 通过视频路径获取AVURLAsset
            NSURL * vedioURL = [NSURL URLWithString:videoPath];
            AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:vedioURL options:nil];
            
            NSParameterAssert(asset);
            AVAssetImageGenerator *assetImageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
            assetImageGenerator.appliesPreferredTrackTransform = YES;
            assetImageGenerator.apertureMode = AVAssetImageGeneratorApertureModeEncodedPixels;
            
            CGImageRef thumbnailImageRef = NULL;
            CFTimeInterval thumbnailImageTime = time;
            NSError *thumbnailImageGenerationError = nil;
            thumbnailImageRef = [assetImageGenerator copyCGImageAtTime:CMTimeMake(thumbnailImageTime, 60) actualTime:NULL error:&thumbnailImageGenerationError];
            
            if (!thumbnailImageRef) {
                NSLog(@"thumbnailImageGenerationError %@", thumbnailImageGenerationError);
            }
            UIImage *thumbnailImage = thumbnailImageRef ? [[UIImage alloc] initWithCGImage:thumbnailImageRef] : nil;
            dispatch_async(dispatch_get_main_queue(), ^{
                success(thumbnailImage);
            });
        });
    }
    

    获取当前设备是iPad还是iPhone

    // 判断是否为pad
    UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad
    
    // 获取当前iPhone型号
    - (NSString*)deviceVersion
    {
        // 需要#import "sys/utsname.h"
        struct utsname systemInfo;
        uname(&systemInfo);
        NSString *deviceString = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
    
        //CLog(@"%@",deviceString);
        if ([deviceString isEqualToString:@"iPhone1,1"])    return @"iPhone 1G";
        if ([deviceString isEqualToString:@"iPhone1,2"])    return @"iPhone 3G";
        if ([deviceString isEqualToString:@"iPhone2,1"])    return @"iPhone 3GS";
        if ([deviceString isEqualToString:@"iPhone3,1"])    return @"iPhone 4";
        if ([deviceString isEqualToString:@"iPhone3,2"])    return @"Verizon iPhone 4";
        if ([deviceString isEqualToString:@"iPhone4,1"])    return @"iPhone 4S";
        if ([deviceString isEqualToString:@"iPhone5,2"])    return @"iPhone 5";
        if ([deviceString isEqualToString:@"iPhone6,2"])    return @"iPhone 5S";
        if ([deviceString isEqualToString:@"iPhone7,2"])    return @"iPhone 6";
        if ([deviceString isEqualToString:@"iPod1,1"])      return @"iPod Touch 1G";
        if ([deviceString isEqualToString:@"iPod2,1"])      return @"iPod Touch 2G";
        if ([deviceString isEqualToString:@"iPod3,1"])      return @"iPod Touch 3G";
        if ([deviceString isEqualToString:@"iPod4,1"])      return @"iPod Touch 4G";
        if ([deviceString isEqualToString:@"iPad1,1"])      return @"iPad";
        if ([deviceString isEqualToString:@"iPad2,1"])      return @"iPad 2 (WiFi)";
        if ([deviceString isEqualToString:@"iPad2,2"])      return @"iPad 2 (GSM)";
        if ([deviceString isEqualToString:@"iPad2,3"])      return @"iPad 2 (CDMA)";
        if ([deviceString isEqualToString:@"iPad3,4"])      return @"iPad 4 (WiFi)";
        if ([deviceString isEqualToString:@"i386"])         return @"Simulator";
        if ([deviceString isEqualToString:@"x86_64"])       return @"Simulator";
    
        //CLog(@"NOTE: Unknown device type: %@", deviceString);
    
        return deviceString;
    }
    

    block

    // 定义
    typedef void (^MyBlock)();
    @property (nonatomic, copy) MyBlock buttonAction;
    
    // 定义
    @property (nonatomic, copy)void(^dimissCompleteBlock)(void);
    
    // 定义
    - (void)checkBlockResult:(void(^)(NSInteger))result;
    
    // block可抽出来:
    // 定义
    - (void)didFinish:(void (^)(void))didFinish;
    // 调用
    [self didFinish:didFinishPlay]]
    // 实现
    void (^didFinishPlay)(void) = ^(){
      
    };
    
    

    判断字符串中是否有表情

    - (BOOL)stringContainsEmoji:(NSString *)string
    {
        __block BOOL returnValue = NO;
        void (^didFinishPlay)() = ^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop){
            const unichar hs = [substring characterAtIndex:0];
            // surrogate pair
            if (0xd800 <= hs && hs <= 0xdbff) {
                if (substring.length > 1) {
                    const unichar ls = [substring characterAtIndex:1];
                    const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
                    if (0x1d000 <= uc && uc <= 0x1f77f) {
                        returnValue = YES;
                    }
                }
            } else if (substring.length > 1) {
                const unichar ls = [substring characterAtIndex:1];
                if (ls == 0x20e3) {
                    returnValue = YES;
                }
            } else {
                // non surrogate
                if (0x2100 <= hs && hs <= 0x27ff) {
                    returnValue = YES;
                } else if (0x2B05 <= hs && hs <= 0x2b07) {
                    returnValue = YES;
                } else if (0x2934 <= hs && hs <= 0x2935) {
                    returnValue = YES;
                } else if (0x3297 <= hs && hs <= 0x3299) {
                    returnValue = YES;
                } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) {
                    returnValue = YES;
                }
            }
        };
    
        [string enumerateSubstringsInRange:NSMakeRange(0, [string length])
                                   options:NSStringEnumerationByComposedCharacterSequences
                                usingBlock:didFinishPlay];
        
        return returnValue;
    }
    

    CALayout图片平铺(可用于AVPlayer的预览图设置)

    self.view.layer.contents = (__bridge id)[UIImage imageNamed:@"demo"].CGImage;
    

    屏幕旋转

    // 允许屏幕自动旋转
    // 该方法在只有UIVIewController的状况下 会被调用
    // 是否允许自转
    - (BOOL)shouldAutorotate
    {
        return YES;
    }
    
    // 当将UIViewController加载到UINavigationController上时 - (BOOL)shouldAutorotate不被调用(解决方案查看下一个方法)
    // 在工程需要中需要调用的控制器中加入下列代码(LoadingViewController)
    @implementation UINavigationController (Rotation_IOS6)
    -(BOOL)shouldAutorotate {
         return [[self.viewControllers lastObject] shouldAutorotate];
    }
    
    -(NSUInteger)supportedInterfaceOrientations
    {
         return [[self.viewControllers lastObject] supportedInterfaceOrientations];
    }
    
    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
    {
         return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
    }
    @end
    
    // 屏幕旋转
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
        return (interfaceOrientation ==  UIInterfaceOrientationLandscapeLeft ||
                interfaceOrientation ==  UIInterfaceOrientationLandscapeRight );
    }
    
    // 屏幕旋转
    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
    {
        return UIInterfaceOrientationPortrait;
    }
    
    // 屏幕支持的方向
    -(NSUInteger)supportedInterfaceOrientations
    {
         return UIInterfaceOrientationMaskLandscape;
    }
    
    // 手动旋转屏幕(电池栏也会跟着旋转)
    if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
         SEL selector = NSSelectorFromString(@"setOrientation:");
         NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
         [invocation setSelector:selector];
         [invocation setTarget:[UIDevice currentDevice]];
         int val = (int)UIInterfaceOrientationLandscapeRight;
         [invocation setArgument:&val atIndex:2];
         [invocation invoke];
    }
    
    // 默认旋转方向
    1.打开项目Supporting Files文件夹中的info.plist
    2.找到Supported interface orientations
    3.改变item的顺序,如果right在前面 left在后面,那么屏幕默认以left方向为准
    

    解决控制器dismiss时,被覆盖的界面自动旋转

    // 1、在 - (void)viewDidLoad 或者 - (void)viewWillAppear:(BOOL)animated中加入以下代码
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
            //orientation
            [[UIApplication sharedApplication]
             setStatusBarOrientation:UIInterfaceOrientationPortrait
             animated:NO];
    
            [[UIDevice currentDevice]
             setValue:[NSNumber
                       numberWithInteger:UIInterfaceOrientationPortrait]
             forKey:@"orientation"];
    }
    
    // 2、重写以下方法
    - (BOOL)shouldAutorotate
    {
        return YES;
    }
    
    - (NSUInteger)supportedInterfaceOrientations
    {
        // 返回所需要的方向,可以是多个方向
        return UIInterfaceOrientationMaskPortrait;
    }
    
    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
    {
        // 返回所需要的方向,可以是多个方向
        returnUIInterfaceOrientationPortrait;
    }
    

    获取启动页和设置启动页延时(LaunchView)

    UIView * launchView =  [[NSBundle mainBundle] loadNibNamed:@"LaunchScreen" owner:nil options:nil][0];
    launchView.frame = CGRectMake(0, 0, ScreenWidth, ScreenHeight);
    [self.window addSubview:launchView];
    [NSThread sleepForTimeInterval:0.4];
    

    点击推送通知进入APP 显示通知内容

    // 当点击推送通知时 下面方法中的launchOptions会有数据
    // 因此可以由此去判断当前是否是点击推送进入的APP
    // 可以设置全局变量来记录
    - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
    
    // 此时必然会调用下面的方法
    // 可以获取userInfo中的内容
    // 字段分别是 alert badge sound
    // 通过userInfo[@"aps"][@"alert”]获取
    - (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
    
    iOS 7.0 用该方法
    - (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    
    // 判断是否通过推送界面进入
    NSDictionary* remoteNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    if (remoteNotification)
    {
         _isLaunchedByNotification = 1;
    }
    

    获取版本号Version

    [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
    [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    

    字体大小自动调整

    // 按钮、标签都可以进行自动调整
    button.titleLabel.adjustsFontSizeToFitWidth = YES;
    // 调增范围(字体大小最多缩小到某个比率)
    button.titleLabel.minimumScaleFactor = 0.5;
    

    获取runtime中的私有属性

    获取下图中红框中的属性名


    私有属性
    // 1.申明一个类目并写好实现逻辑
    @interface NSObject (RuntimeUntility)
    - (id)getPrivateProperty:(NSString *)propertyName;
    @end
    
    @implementation NSObject (RuntimeUntility)
    - (id)getPrivateProperty:(NSString *)propertyName
    {
        Ivar iVar = class_getInstanceVariable([self class], [propertyName UTF8String]);
        
        if (iVar == nil) {
            iVar = class_getInstanceVariable([self class], [[NSString stringWithFormat:@"_%@",propertyName] UTF8String]);
        }
        
        id propertyVal = object_getIvar(self, iVar);
        return propertyVal;
    }
    @end
    
    
    // 2.进行调用,传入参数填写要获取的属性的名称,如果runtime中有有下滑线(如_bqmmExtra)要对其删除
    id bqmmExtra = [messageContent getPrivateProperty:@"bqmmExtra"];
    
    

    pragma mark - 安装包获

    1.打开活动监视器
    2.找到storedownload
    3.点击图标



    4.复制一下路径,到指定路径下获取包,在安装之前把他拖出来


    处理本地缓存

    1.搜索路径:/Users/huangyuzhou(用户名)/Library/Developer/Xcode
    (注:Library资源库是隐藏的文件夹)
    2.删除里面文件即可(里面有DerivedData和Snapshots两个文件夹,)

    自动内存管理 手动内存管理混编

    可以在build phases 下的compile sources 中找到不想自动管理的.m文件 ,给它加compiler flags 为 -fno-objc-arc

    Xcode真机调试包

    Xcode版本不支持高版本手机时,可拖入高版本包,从而不需要更新Xcode,而进行真机测试。路径:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

    正则表达式

    // 含有字母和数字的6~16位字符串
    NSString * passwordRegex = @"^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$";
    

    模糊效果

    //加模糊效果,image是图片,blur是模糊度
    - (UIImage *)blurryImage:(UIImage *)image withBlurLevel:(CGFloat)blur {
        //模糊度,
        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;
        //需要引入
        /*
         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;
    }
    

    Gif图的两种播放方式

    #import "ViewController.h"
    #import <WebKit/WebKit.h>
    #import <ImageIO/ImageIO.h>
    
    /*
     经过测试,从加载速度上来说,通过UIImageView类别加载的方式更加快速,UIWebView的方式加载时间会稍长,但是从性能上来比较,WebView的方式性能更优,播放的gif动态图更加流畅。
     在开发中,可以根据需求,适当选择,例如虽然WebView加载的方式性能更好,但是在许多情况下,原生的UIImageView能够更加自由的让开发者进行扩展。
     */
    
    /*
      UIImage+GitImageView
    */
    @interface UIImageView (GitImageView)
    @end
    
    @implementation UIImageView (GitImageView)
    
    // 为UIImageView添加一个设置gif图内容的方法:
    -(void)yh_setImage:(NSURL *)imageUrl{
        __weak id __self = self;
        [self getGifImageWithUrk:imageUrl returnData:^(NSArray<UIImage *> *imageArray, NSArray<NSNumber *> *timeArray, CGFloat totalTime, NSArray<NSNumber *> *widths, NSArray<NSNumber *> *heights) {
            // 展示第一张图片
            if (0) {
                UIImage * image = imageArray[0];
                self.image = image;
            }
            // 展示帧动画
            else{
                //添加帧动画
                CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
                NSMutableArray * times = [[NSMutableArray alloc]init];
                float currentTime = 0;
                
                NSMutableArray * imageRefs = [NSMutableArray array];
                for (UIImage * newImage in imageArray) {
                    CGImageRef imageRef = newImage.CGImage;
                    [imageRefs addObject:(__bridge UIImage *)imageRef];
                }
                //设置每一帧的时间占比
                for (int i=0; i<imageRefs.count; i++) {
                    [times addObject:[NSNumber numberWithFloat:currentTime/totalTime]];
                    currentTime+=[timeArray[i] floatValue];
                }
                [animation setKeyTimes:times];
                [animation setValues:imageRefs];
                [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
                //设置循环
                animation.repeatCount= MAXFLOAT;
                //设置播放总时长
                animation.duration = totalTime;
                //Layer层添加
                [[(UIImageView *)__self layer]addAnimation:animation forKey:@"gifAnimation"];
            }
        }];
    }
    
    //解析gif文件数据的方法 block中会将解析的数据传递出来
    -(void)getGifImageWithUrk:(NSURL *)url
                   returnData:(void(^)(NSArray<UIImage *> * imageArray,
                                       NSArray<NSNumber *>*timeArray,
                                       CGFloat totalTime,
                                       NSArray<NSNumber *>* widths,
                                       NSArray<NSNumber *>* heights))dataBlock{
        //通过文件的url来将gif文件读取为图片数据引用
        CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)url, NULL);
        
        //获取gif文件中图片的个数
        size_t count = CGImageSourceGetCount(source);
        
        //定义一个变量记录gif播放一轮的时间
        float allTime=0;
        
        //存放所有图片
        NSMutableArray * imageArray = [[NSMutableArray alloc]init];
        
        //存放每一帧播放的时间
        NSMutableArray * timeArray = [[NSMutableArray alloc]init];
        
        //存放每张图片的宽度 (一般在一个gif文件中,所有图片尺寸都会一样)
        NSMutableArray * widthArray = [[NSMutableArray alloc]init];
        
        //存放每张图片的高度
        NSMutableArray * heightArray = [[NSMutableArray alloc]init];
        //遍历
        for (size_t i=0; i<count; i++) {
            CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, i, NULL);
            UIImage * image = [UIImage imageWithCGImage:imageRef];
            [imageArray addObject:image];
            CGImageRelease(imageRef);
            //获取图片信息
            NSDictionary * info = (__bridge NSDictionary*)CGImageSourceCopyPropertiesAtIndex(source, i, NULL);
            CGFloat width = [[info objectForKey:(__bridge NSString *)kCGImagePropertyPixelWidth] floatValue];
            CGFloat height = [[info objectForKey:(__bridge NSString *)kCGImagePropertyPixelHeight] floatValue];
            [widthArray addObject:[NSNumber numberWithFloat:width]];
            [heightArray addObject:[NSNumber numberWithFloat:height]];
            NSDictionary * timeDic = [info objectForKey:(__bridge NSString *)kCGImagePropertyGIFDictionary];
            CGFloat time = [[timeDic objectForKey:(__bridge NSString *)kCGImagePropertyGIFDelayTime]floatValue];
            allTime+=time;
            [timeArray addObject:[NSNumber numberWithFloat:time]];
        }
        CFRelease(source);
        dataBlock(imageArray,timeArray,allTime,widthArray,heightArray);
    }
    
    @end
    
    @interface ViewController ()
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // 加载Gif图方法一:使用webView加载,需要导入#import <WebKit/WebKit.h>
        WKWebView * webView = [[WKWebView alloc] initWithFrame:CGRectMake(100, 100, 150, 150)];
        [self.view addSubview:webView];
        NSURL * URL = [NSURL URLWithString:@"http://qq.yh31.com/tp/zr/zr168.gif"];
        NSURLRequest * request = [NSURLRequest requestWithURL:URL];
        [webView loadRequest:request];
        // 取消回弹效果
        webView.scrollView.bounces=NO;
        webView.backgroundColor = [UIColor clearColor];
        // 设置缩放模式
        webView.userInteractionEnabled = NO;
        
        
        // 加载Gif图方法二:使用ImageIO库
        UIImageView * imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100 ,300 , 150, 150)];
        NSURL * url = URL;
        [imageView yh_setImage:url];
        [self.view addSubview:imageView];
    }
    
    
    @end
    

    自定义代码模板

    1. 进入到/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/File Templates/Source目录下
    2. 任意拷贝其中一个模板,并改名为MyClass.xctemplate,后缀.xctemplate新建文件试试,是不是有MyClass这个文件模板了呢

    快捷打包方式

    1. 切换到图中的情况,进行commond + B 编译一次。


    2. 找到图中.app后缀的文件,到文件所在路径,将文件拷贝一份到桌面


    3. 在桌面创建一个名为"Payload"的文件夹,将刚刚的.app文件拖入,然后压缩,压缩完成后将安装包后缀改成.ipa


    文件/文件夹隐藏

    文件/文件夹隐藏

    相关文章

      网友评论

          本文标题:iOS 开发记录

          本文链接:https://www.haomeiwen.com/subject/dytzgttx.html