iOS 開發(fā)記錄

打印方法名

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

類、方法判斷

// 用于判斷是否包含某個(gè)類方法
respondsToSelector:(SEL)                      

conformsToProtocol:(Protocol *)          
 // 判定某個(gè)類     
isKindOfClass:(__unsafe_unretained Class)    

isMemberOfClass:(__unsafe_unretained Class)   

// 獲取某個(gè)類的類名字符串
NSStringFromClass([UITextView class]);

// 通過(guò)字符串獲取某個(gè)類
NSClassFromString(@"UITextView");

emoji表情轉(zhuǎn)換

// 表情轉(zhuǎn)UTF8
[contentstringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

// UTF8轉(zhuǎn)表情
[content stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

數(shù)組和字典與NSData互轉(zhuǎn)

NSArray * arr1 = [[NSArray alloc]initWithObjects:@"0",@"5",nil];

// NSArray->NSData(轉(zhuǎn)字典也使用該方法)
NSData  * data = [NSKeyedArchiver archivedDataWithRootObject:arr1];

// NSData->NSArray(轉(zhuǎn)字典也使用該方法)
NSArray * arr2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];

字典、JSON互轉(zhuǎn)

// json格式字符串轉(zhuǎn)字典:
+ (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;
}

// 字典轉(zhuǎn)json格式字符串:
+ (NSString*)dictionaryToJson:(NSDictionary *)dic
{
    NSError *parseError = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&parseError];
    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}

自定義結(jié)構(gòu)體(類似于CGSizeMake)

/**
 *  分頁(yè)
 */
struct LBPage{
    NSInteger page;
    NSInteger number;
};
typedef struct LBPage LBPage;

/**
 *  創(chuàng)建分頁(yè)結(jié)構(gòu)體
 */
CG_INLINE LBPage
LBPageMake(NSInteger page, NSInteger number)
{
  LBPage p;
  p.page = page; 
  p.number = number; 
  return p;
}

實(shí)現(xiàn)多選參數(shù)(如UIAlertView初始化)

// 定義方法:
- (void)buttonTitles:(nullable NSString *)titles,...;

// 實(shí)現(xiàn)方法
- (void)buttonTitles:(nullableNSString *)titles,...{
  NSString *other = nil;
  va_list args; //用于指向第一個(gè)參數(shù)
  NSMutableArray *fruits = [NSMutableArray array];
  if(titles){
    [fruits addObject:titles];
    // 對(duì)args進(jìn)行初始化,讓它指向可變參數(shù)表里面的第一個(gè)參數(shù)
    va_start(args, titles);
    // 獲取指定類型的值
    while((other = va_arg(args, NSString*))){
      [fruits addObject:other];
    }
    va_end(args);//將args關(guān)閉
  }
  NSLog(@"%@", fruits);
}

// 方法調(diào)用
[self buttonTitles:@“1”,@“2”,nil];

判斷當(dāng)前設(shè)備是模擬器還是真機(jī)

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

調(diào)試打印

#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;

統(tǒng)音量控制(通過(guò)UISlider直接控制系統(tǒng)音量)

// 導(dǎo)入頭文件
#import <MediaPlayer/MediaPlayer.h> 

// 控制系統(tǒng)音量只需要對(duì)slider進(jìn)行控制即可控制
MPVolumeView *volumeView = [[MPVolumeView alloc] init];
[volumeView sizeToFit];
NSLog(@"%@",volumeView.subviews);

// 將系統(tǒng)的音量調(diào)整視圖賦給自定義的UISlider,實(shí)現(xiàn)拖動(dòng)自定義UISlider直接改變系統(tǒng)音量
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);

獲取系統(tǒng)音量

#import <AVFoundation/AVFoundation.h> 監(jiān)聽系統(tǒng)音量

// 創(chuàng)建監(jiān)聽
NSError *error;
[[AVAudioSession sharedInstance] setActive:YES error:&error];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(volumeChanged:)
                                             name:@"AVSystemController_SystemVolumeDidChangeNotification"
                                           object:nil];

// 開始接收遠(yuǎn)程控制事件
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

// 結(jié)束接收遠(yuǎn)程控制事件
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];

// 獲取音量
- (void)volumeChanged:(NSNotification *)notification
{
     NSLog(@"volume = %@",notification.userInfo);
}

截取當(dāng)前屏幕

// currentView 當(dāng)前的view  創(chuàng)建一個(gè)基于位圖的圖形上下文并指定大小為
UIGraphicsBeginImageContext(self.view.bounds.size);

// renderInContext呈現(xiàn)接受者及其子范圍到指定的上下文
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];

// 返回一個(gè)基于當(dāng)前圖形上下文的圖片
_currentScreen = UIGraphicsGetImageFromCurrentImageContext();

// 移除棧頂?shù)幕诋?dāng)前位圖的圖形上下文
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, ^{
        // 通過(guò)視頻路徑獲取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);
        });
    });
}

獲取當(dāng)前設(shè)備是iPad還是iPhone

// 判斷是否為pad
UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad

// 獲取當(dāng)前iPhone型號(hào)
- (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可抽出來(lái):
// 定義
- (void)didFinish:(void (^)(void))didFinish;
// 調(diào)用
[self didFinish:didFinishPlay]]
// 實(shí)現(xiàn)
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的預(yù)覽圖設(shè)置)

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

屏幕旋轉(zhuǎn)

// 允許屏幕自動(dòng)旋轉(zhuǎn)
// 該方法在只有UIVIewController的狀況下 會(huì)被調(diào)用
// 是否允許自轉(zhuǎn)
- (BOOL)shouldAutorotate
{
    return YES;
}

// 當(dāng)將UIViewController加載到UINavigationController上時(shí) - (BOOL)shouldAutorotate不被調(diào)用(解決方案查看下一個(gè)方法)
// 在工程需要中需要調(diào)用的控制器中加入下列代碼(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

// 屏幕旋轉(zhuǎn)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation ==  UIInterfaceOrientationLandscapeLeft ||
            interfaceOrientation ==  UIInterfaceOrientationLandscapeRight );
}

// 屏幕旋轉(zhuǎn)
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationPortrait;
}

// 屏幕支持的方向
-(NSUInteger)supportedInterfaceOrientations
{
     return UIInterfaceOrientationMaskLandscape;
}

// 手動(dòng)旋轉(zhuǎn)屏幕(電池欄也會(huì)跟著旋轉(zhuǎn))
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];
}

// 默認(rèn)旋轉(zhuǎn)方向
1.打開項(xiàng)目Supporting Files文件夾中的info.plist
2.找到Supported interface orientations
3.改變item的順序,如果right在前面 left在后面,那么屏幕默認(rèn)以left方向?yàn)闇?zhǔn)

解決控制器dismiss時(shí),被覆蓋的界面自動(dòng)旋轉(zhuǎn)

// 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
{
    // 返回所需要的方向,可以是多個(gè)方向
    return UIInterfaceOrientationMaskPortrait;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    // 返回所需要的方向,可以是多個(gè)方向
    returnUIInterfaceOrientationPortrait;
}

獲取啟動(dòng)頁(yè)和設(shè)置啟動(dòng)頁(yè)延時(shí)(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];

點(diǎn)擊推送通知進(jìn)入APP 顯示通知內(nèi)容

// 當(dāng)點(diǎn)擊推送通知時(shí) 下面方法中的launchOptions會(huì)有數(shù)據(jù)
// 因此可以由此去判斷當(dāng)前是否是點(diǎn)擊推送進(jìn)入的APP
// 可以設(shè)置全局變量來(lái)記錄
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions

// 此時(shí)必然會(huì)調(diào)用下面的方法
// 可以獲取userInfo中的內(nèi)容
// 字段分別是 alert badge sound
// 通過(guò)userInfo[@"aps"][@"alert”]獲取
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo

iOS 7.0 用該方法
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler

// 判斷是否通過(guò)推送界面進(jìn)入
NSDictionary* remoteNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (remoteNotification)
{
     _isLaunchedByNotification = 1;
}

獲取版本號(hào)Version

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

字體大小自動(dòng)調(diào)整

// 按鈕、標(biāo)簽都可以進(jìn)行自動(dòng)調(diào)整
button.titleLabel.adjustsFontSizeToFitWidth = YES;
// 調(diào)增范圍(字體大小最多縮小到某個(gè)比率)
button.titleLabel.minimumScaleFactor = 0.5;

獲取runtime中的私有屬性

獲取下圖中紅框中的屬性名


私有屬性
// 1.申明一個(gè)類目并寫好實(shí)現(xiàn)邏輯
@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.進(jìn)行調(diào)用,傳入?yún)?shù)填寫要獲取的屬性的名稱,如果runtime中有有下滑線(如_bqmmExtra)要對(duì)其刪除
id bqmmExtra = [messageContent getPrivateProperty:@"bqmmExtra"];

pragma mark - 安裝包獲

1.打開活動(dòng)監(jiān)視器
2.找到storedownload
3.點(diǎn)擊圖標(biāo)



4.復(fù)制一下路徑,到指定路徑下獲取包,在安裝之前把他拖出來(lái)


處理本地緩存

1.搜索路徑:/Users/huangyuzhou(用戶名)/Library/Developer/Xcode
(注:Library資源庫(kù)是隱藏的文件夾)
2.刪除里面文件即可(里面有DerivedData和Snapshots兩個(gè)文件夾,)

自動(dòng)內(nèi)存管理 手動(dòng)內(nèi)存管理混編

可以在build phases 下的compile sources 中找到不想自動(dòng)管理的.m文件 ,給它加compiler flags 為 -fno-objc-arc

Xcode真機(jī)調(diào)試包

Xcode版本不支持高版本手機(jī)時(shí),可拖入高版本包,從而不需要更新Xcode,而進(jìn)行真機(jī)測(cè)試。路徑:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

正則表達(dá)式

// 含有字母和數(shù)字的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語(yǔ)言應(yīng)用程序接口(API)的向量和矩陣數(shù)學(xué),數(shù)字信號(hào)處理,大量處理和圖像處理。
     */
    
    //圖像緩存,輸入緩存,輸出緩存
    vImage_Buffer inBuffer, outBuffer;
    vImage_Error error;
    //像素緩存
    void *pixelBuffer;
    
    //數(shù)據(jù)源提供者,Defines an opaque type that supplies Quartz with data.
    CGDataProviderRef inProvider = CGImageGetDataProvider(img);
    // provider’s data.
    CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
    
    //寬,高,字節(jié)/行,data
    inBuffer.width = CGImageGetWidth(img);
    inBuffer.height = CGImageGetHeight(img);
    inBuffer.rowBytes = CGImageGetBytesPerRow(img);
    inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);
    
    //像數(shù)緩存,字節(jié)行*圖片高
    pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));
    
    outBuffer.data = pixelBuffer;
    outBuffer.width = CGImageGetWidth(img);
    outBuffer.height = CGImageGetHeight(img);
    outBuffer.rowBytes = CGImageGetBytesPerRow(img);
    
    
    // 第三個(gè)中間的緩存區(qū),抗鋸齒的效果
    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(@"字節(jié)組成部分:%zu",CGImageGetBitsPerComponent(img));
    //顏色空間DeviceRGB
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    //用圖片創(chuàng)建上下文,CGImageGetBitsPerComponent(img),7,8
    CGContextRef ctx = CGBitmapContextCreate(
                                             outBuffer.data,
                                             outBuffer.width,
                                             outBuffer.height,
                                             8,
                                             outBuffer.rowBytes,
                                             colorSpace,
                                             CGImageGetBitmapInfo(image.CGImage));
    
    //根據(jù)上下文,處理過(guò)的圖片,重新組件
    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>

/*
 經(jīng)過(guò)測(cè)試,從加載速度上來(lái)說(shuō),通過(guò)UIImageView類別加載的方式更加快速,UIWebView的方式加載時(shí)間會(huì)稍長(zhǎng),但是從性能上來(lái)比較,WebView的方式性能更優(yōu),播放的gif動(dòng)態(tài)圖更加流暢。
 在開發(fā)中,可以根據(jù)需求,適當(dāng)選擇,例如雖然WebView加載的方式性能更好,但是在許多情況下,原生的UIImageView能夠更加自由的讓開發(fā)者進(jìn)行擴(kuò)展。
 */

/*
  UIImage+GitImageView
*/
@interface UIImageView (GitImageView)
@end

@implementation UIImageView (GitImageView)

// 為UIImageView添加一個(gè)設(shè)置gif圖內(nèi)容的方法:
-(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;
        }
        // 展示幀動(dòng)畫
        else{
            //添加幀動(dòng)畫
            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];
            }
            //設(shè)置每一幀的時(shí)間占比
            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]];
            //設(shè)置循環(huán)
            animation.repeatCount= MAXFLOAT;
            //設(shè)置播放總時(shí)長(zhǎng)
            animation.duration = totalTime;
            //Layer層添加
            [[(UIImageView *)__self layer]addAnimation:animation forKey:@"gifAnimation"];
        }
    }];
}

//解析gif文件數(shù)據(jù)的方法 block中會(huì)將解析的數(shù)據(jù)傳遞出來(lái)
-(void)getGifImageWithUrk:(NSURL *)url
               returnData:(void(^)(NSArray<UIImage *> * imageArray,
                                   NSArray<NSNumber *>*timeArray,
                                   CGFloat totalTime,
                                   NSArray<NSNumber *>* widths,
                                   NSArray<NSNumber *>* heights))dataBlock{
    //通過(guò)文件的url來(lái)將gif文件讀取為圖片數(shù)據(jù)引用
    CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)url, NULL);
    
    //獲取gif文件中圖片的個(gè)數(shù)
    size_t count = CGImageSourceGetCount(source);
    
    //定義一個(gè)變量記錄gif播放一輪的時(shí)間
    float allTime=0;
    
    //存放所有圖片
    NSMutableArray * imageArray = [[NSMutableArray alloc]init];
    
    //存放每一幀播放的時(shí)間
    NSMutableArray * timeArray = [[NSMutableArray alloc]init];
    
    //存放每張圖片的寬度 (一般在一個(gè)gif文件中,所有圖片尺寸都會(huì)一樣)
    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加載,需要導(dǎo)入#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];
    // 設(shè)置縮放模式
    webView.userInteractionEnabled = NO;
    
    
    // 加載Gif圖方法二:使用ImageIO庫(kù)
    UIImageView * imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100 ,300 , 150, 150)];
    NSURL * url = URL;
    [imageView yh_setImage:url];
    [self.view addSubview:imageView];
}


@end

自定義代碼模板

  1. 進(jìn)入到/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/File Templates/Source目錄下
  2. 任意拷貝其中一個(gè)模板,并改名為MyClass.xctemplate,后綴.xctemplate新建文件試試,是不是有MyClass這個(gè)文件模板了呢

快捷打包方式

  1. 切換到圖中的情況,進(jìn)行commond + B 編譯一次。


  2. 找到圖中.app后綴的文件,到文件所在路徑,將文件拷貝一份到桌面


  3. 在桌面創(chuàng)建一個(gè)名為"Payload"的文件夾,將剛剛的.app文件拖入,然后壓縮,壓縮完成后將安裝包后綴改成.ipa


文件/文件夾隱藏

文件/文件夾隱藏

保證計(jì)時(shí)器在切換到后臺(tái)時(shí),還能繼續(xù)運(yùn)行

#pragma mark - 程序進(jìn)入后臺(tái)后 繼續(xù)倒計(jì)時(shí)功能
//程序進(jìn)入后臺(tái)不會(huì)影響到計(jì)時(shí)功能
- (void)beginBackGroundTask:(UIApplication *)application {
    self.bgIdentifier =[application beginBackgroundTaskWithExpirationHandler:^(void) {
        
        // 當(dāng)應(yīng)用程序留給后臺(tái)的時(shí)間快要到結(jié)束時(shí)(應(yīng)用程序留給后臺(tái)執(zhí)行的時(shí)間是有限的), 這個(gè)Block塊將被執(zhí)行
        // 我們需要在次Block塊中執(zhí)行一些清理工作。
        // 如果清理工作失敗了,那么將導(dǎo)致程序掛掉
        // 清理工作需要在主線程中用同步的方式來(lái)進(jìn)行
        dispatch_queue_t mainQueue = dispatch_get_main_queue();
        AppDelegate *weakSelf = self;
        dispatch_async(mainQueue, ^(void) {
            
            AppDelegate *strongSelf = weakSelf;
            if (strongSelf != nil){
                [self endBackGroundTask];
            }
        });
    }];
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
//    [super applicationDidEnterBackground:application];
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    
    [self beginBackGroundTask:application];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    //application.applicationIconBadgeNumber = 0;
    
    [self endBackGroundTask];
    
}
//結(jié)束程序進(jìn)入后臺(tái)的任務(wù)
- (void)endBackGroundTask {
    // 每個(gè)對(duì) beginBackgroundTaskWithExpirationHandler:方法的調(diào)用,必須要相應(yīng)的調(diào)用 endBackgroundTask:方法。這樣,來(lái)告訴應(yīng)用程序你已經(jīng)執(zhí)行完成了。
    // 也就是說(shuō),我們向 iOS 要更多時(shí)間來(lái)完成一個(gè)任務(wù),那么我們必須告訴 iOS 你什么時(shí)候能完成那個(gè)任務(wù)。
    // 也就是要告訴應(yīng)用程序:“好借好還”嘛。
    // 標(biāo)記指定的后臺(tái)任務(wù)完成
    [[UIApplication sharedApplication] endBackgroundTask:self.bgIdentifier];
    // 銷毀后臺(tái)任務(wù)標(biāo)識(shí)符
    self.bgIdentifier = UIBackgroundTaskInvalid;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift版本點(diǎn)擊這里歡迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh閱讀 25,990評(píng)論 7 249
  • 從前,你說(shuō),時(shí)光很慢 你喜歡一個(gè)人坐在階前 摘花,聽雨 像個(gè)安靜的少年 那些從遠(yuǎn)方飄來(lái)的信箋 滿載著深深思念 卻在...
    邊城幻影閱讀 315評(píng)論 27 5
  • 科學(xué)界有一種主流說(shuō)法,地球原本沒(méi)有水,是因一顆彗星(由大量冰凝結(jié)而成)撞到地球上,這顆土球才變?yōu)橐活w蔚藍(lán)星球。在后...
    裸足閱讀 910評(píng)論 0 0
  • 很多的職業(yè)經(jīng)理人是從基層出身的,有著一身摸爬滾打的好本事,實(shí)務(wù)經(jīng)驗(yàn)非常豐富,堪稱為一員猛將,但是一碰到電腦,有時(shí)候...
    周明達(dá)老師閱讀 1,075評(píng)論 0 6

友情鏈接更多精彩內(nèi)容