iOS开发经验与总结iOS进阶之路

知识点2

2016-10-31  本文已影响179人  DDY

虽不才,关注下吧,防止你用到了,有问题连个商量的人都找不到...

101.PDF

// 获取沙盒地址
NSArray *pathArr=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *str=pathArr[0];
//创建的文件地址
NSString *path=[str stringByAppendingPathComponent:@”image.pdf”];
NSLog(@”%@”,path);
//创建PDF图形上下文
UIGraphicsBeginPDFContextToFile(path, CGRectZero, NULL);
//给PDF文件添加内容 612 *792
for (int i=0; i<6; i++) {
if (i%2==0) {
        //重新创建新的一页
        UIGraphicsBeginPDFPage();
}
UIImage *image=[UIImage imageNamed:[NSString stringWithFormat:@”%d_full.jpg”,i]];
//调用这个方法的时候,会把图片绘制到当前页
[image drawInRect:CGRectMake(0, 396*(i%2), 612, 396)];
}
//关闭图形上下文
UIGraphicsEndPDFContext();
}

102.系统声音并震动

// 需要 #import <AudioToolbox/AudioToolbox.h>
AudioServicesPlaySystemSound(1007); //系统的通知声音,只有声音并震动模式才自带震动
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);//震动

103.iOS9 以上50个scheme限制问题

canOpenUrl可以用来判断用户是否安装了某个APP。也许是出于用户隐私的考虑,iOS9上对canOpenUrl做了限制,最多只能对50个scheme做判断。
需要在plist里面声明这些scheme,没有声明的会直接返回NO,所以在iOS9beta刚出来的时候,有些用户无法从微信跳转到第三方app,就是因为已经达到了限制数量,系统直接返回NO,程序以为用户没有安装该APP,就没有去跳转。
解决办法是加白名单,并且尽量减少不必要的canOpenUrl调用,以免超过50个名额的限制。
然后 if (!openUrl(scheme)) then xxx;

104.图片局部拉伸

[[UIImage imageNamed:@""] stretchableImageWithLeftCapWidth:10 topCapHeight:10];
[[UIImage imageNamed:@""] resizableImageWithCapInsets:UIEdgeInsetsMake(10, 10, 10, 10)];

.

105.苹果自带的多行注释(iOS8 later)

Command + Option + / (开启方式sudo /usr/libexec/xpccachectl)

106.热更新会不会被拒

苹果禁止的是“基于反射的热更新“,而不是 “基于沙盒接口的热更新”。而大部分的应用框架(如 React-Native)和游戏引擎(比如 Unity ,Cocos2d-x,白鹭引擎等)都属于后者,所以不在被警告范围内。参见知乎

107.double精度血案

    double a = 2.01;
    double b = 1.02;
    double c = a - b;
    DDYInfoLog(@"%@",@(c));
    DDYInfoLog(@"%lf",c);
    if (c == 0.99)
    {
        DDYInfoLog(@"double 0.99"); // 不打印
    }
    if (c == 0.98999999999999976)
    {
        DDYInfoLog(@"double 0.98999999999999976");// 打印
    }
    if ([[NSString stringWithFormat:@"%g",c] isEqualToString:@"0.99"])
    {
        DDYInfoLog(@"string 0.99");// 打印
    }

108.查看是否违反热更新

This code, combined with a remote resource, can facilitate significant changes to your app’s behavior compared to when it was initially reviewed for the App Store. While you may not be using this functionality currently, it has the potential to load private frameworks, private methods, and enable future feature changes. This includes any code which passes arbitrary parameters to dynamic methods such as dlopen(), dlsym(), respondsToSelector:, performSelector:, method_exchangeImplementations(), and running remote scripts in order to change app behavior and/or call SPI, based on the contents of the downloaded script. Even if the remote resource is not intentionally malicious, it could easily be hijacked via a Man In The Middle (MiTM) attack, which can pose a serious security vulnerability to users of your app.

nm -u libName.a >> xxx.txt, 然后查找dlopen  、 dlsym

109.私有API被拒,查看哪些库用到了这些私有API

grep -r 涉及的api名字 工程所在的文件地址
例如: grep -r UIPeripheralHostView /Users/634778311/Desktop/app_ios

110.傻逼苹果不懂你的流程,让你录制视屏,录制后还被要求录制

要把苹果审核人员当十足的傻逼才行,也就是录制必须从登录注册这里开始到达你真的需要展示给审核人员的地方,同时备注加图片解释

111.沙盒视屏保存到相册

// 姿势1
 if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(video_path))
 {
                UISaveVideoAtPathToSavedPhotosAlbum(video_path, self, @selector(video:didFinishSavingWithError:contextInfo:), nil);
            }

// 姿势2
 ALAssetsLibrary *library  = [[ALAssetsLibrary alloc] init];
        [library writeVideoAtPathToSavedPhotosAlbum:filePath  completionBlock:^(NSURL *assetURL, NSError *error) {
            if (error) {
                NSLog(@"Save video fail:%@",error);
            } else {
                NSLog(@"Save video succeed.");
                NSFileManager *fileManger = [[NSFileManager alloc] init];
                [fileManger removeItemAtURL:filePath error:nil];
            }
        }];

112.禁用第三方键盘(APPDelegate)

#pragma mark - 禁用第三方键盘
- (BOOL)application:(UIApplication
*)application shouldAllowExtensionPointIdentifier:(NSString
*)extensionPointIdentifier {
    return NO;
}

113.获取启动图的名称[项目启动后会对launchImage中的图片进行2次命名]

- (NSString *)fetchLaunchImageName
{
    NSArray* imagesDict = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"UILaunchImages"];
    for (NSDictionary* dict in imagesDict) {
        if(CGSizeEqualToSize(CGSizeFromString(dict[@"UILaunchImageSize"]),[UIScreen mainScreen].bounds.size))
        {
            return dict[@"UILaunchImageName"];
        }
    }
    return nil;
}

114.iOS 从网页缓存中获取图片

- (void)webViewDidFinishLoad:(UIWebView *)webView{
    NSArray *a=[self getImgs];
    for (NSString *str in a) {
        NSURLCache *sharedCache = (NSURLCache *)[NSURLCache sharedURLCache];
        NSURLSession *session = [NSURLSession sharedSession];
        NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:str]];
        __block NSString *wstr = str;
        [sharedCache getCachedResponseForDataTask:task completionHandler:^(NSCachedURLResponse * _Nullable cachedResponse) {
            NSString *path = [NSString stringWithFormat:@"/Users/whde/Desktop/t/%@", [wstr lastPathComponent]];
            [cachedResponse.data writeToFile:path options:NSDataWritingAtomic error:nil];

        }];
    }
}
//  获取所有图片链接
- (NSArray *)getImgs
{
    NSMutableArray *arrImgURL = [[NSMutableArray alloc] init];
    for (int i = 0; i < [self nodeCountOfTag:@"img"]; i++) {
        NSString *jsString = [NSString stringWithFormat:@"document.getElementsByTagName('img')[%d].src", i];
        [arrImgURL addObject:[webView stringByEvaluatingJavaScriptFromString:jsString]];
    }
    return arrImgURL;
}
//  获取某个标签的结点个数
- (int)nodeCountOfTag:(NSString *)tag
{
    NSString *jsString = [NSString stringWithFormat:@"document.getElementsByTagName('%@').length", tag];
    int len = [[webView stringByEvaluatingJavaScriptFromString:jsString] intValue];
    return len;
}

115.控制器生命周期

1 + (void)initialize;
2 - (instancetype)init;
3 - (void)loadView;
4 - (void)viewDidLoad;
5 -(void)viewWillLayoutSubviews;
6 -(void)viewDidLayoutSubviews;
7 - (void)viewWillAppear:(BOOL)animated;
8 - (void)viewDidAppear:(BOOL)animated
9 - (void)viewWillDisAppear:(BOOL)animated;
10 - (void)viewDidDisAppear:(BOOL)animated;
11 - (void)dealloc;

116.UITableView iOS8 later 蒙层

tableview.backgroundView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"detail.jpg"]];
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
UIVibrancyEffect *vibrancyEffect = [UIVibrancyEffect effectForBlurEffect:blurEffect];
tableview.separatorEffect = vibrancyEffect;

117. 视图镂空(遮罩,相机)

holeView.png

自定义视图初始化时调用

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self setupContentView];
    }
    return self;
}

方法实现

- (void)setupContentView
{
    CGMutablePathRef path =CGPathCreateMutable();
    CGPathAddRect(path, nil, self.bounds);
    CGPathAddRect(path, nil, CGRectMake(DDYSCREENW/2.0-120, 140, 240, 240));
    // CGPathAddArc(path, nil, DDYSCREENW/2.0, DDYSCREENH/2.0, 120, 0, 2*M_PI, 0);  // 圆形
    
    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = path;
    shapeLayer.fillRule = kCAFillRuleEvenOdd;
    shapeLayer.fillColor = DDYColor(0, 0, 0, 0.5).CGColor;
    [self.layer addSublayer:shapeLayer];
}

或者

- (void)setupContentView
{
    UIBezierPath *screenPath = [UIBezierPath bezierPathWithRect:self.bounds];
    UIBezierPath *rectPath = [UIBezierPath bezierPathWithRect:CGRectMake(DDYSCREENW/2.0-80, 160, 160, 160)];
    // [UIBezierPath bezierPathWithArcCenter:]; // 圆形
    [screenPath appendPath:rectPath];
    
    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.fillColor = DDYColor(0, 0, 0, 0.5).CGColor;
    shapeLayer.path = screenPath.CGPath;
    shapeLayer.fillRule = kCAFillRuleEvenOdd;
    [self.layer addSublayer:shapeLayer];
}

118. 去除Pointer is missing a nullability type specifier...警告

NS_ASSUME_NONNULL_BEGIN
// 中间为爆警告的属性或方法定义
NS_ASSUME_NONNULL_END

http://www.jianshu.com/p/83525d8c834f

119.字典转字符串

#pragma mark 字典/数组转json字符串
- (NSString *)ddy_ChangeToJsonString:(id)obj {
    if ([obj isKindOfClass:[NSArray class]] || [obj isKindOfClass:[NSDictionary class]]) {
        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:obj options:NSJSONWritingPrettyPrinted error:nil];
        return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    return @"";
}

//  [data dataUsingEncoding:NSUTF8StringEncoding];

解决NSData转NSString返回nil的问题

120.SHA3 Keccak-256加密/SHA256加密

#pragma mark SHA256加密 http://www.jianshu.com/p/157d84c2d020
- (NSString *)ddy_SHA256 {
    const char *s = [self cStringUsingEncoding:NSASCIIStringEncoding];
    NSData *keyData = [NSData dataWithBytes:s length:strlen(s)];
    
    uint8_t digest[CC_SHA256_DIGEST_LENGTH] = {0};
    CC_SHA256(keyData.bytes, (CC_LONG)keyData.length, digest);
    NSData *out = [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];
    NSString *hash = [out description];
    hash = [hash stringByReplacingOccurrencesOfString:@" " withString:@""];
    hash = [hash stringByReplacingOccurrencesOfString:@"<" withString:@""];
    hash = [hash stringByReplacingOccurrencesOfString:@">" withString:@""];
    return hash;
}

#pragma mark SHA3 Keccak-256加密 bitsLength:224/256/384/512
- (NSString *)ddy_SHA3:(NSUInteger)bitsLength
{
    int bytes = (int)(bitsLength/8);
    const char * string = [self cStringUsingEncoding:NSUTF8StringEncoding];
    int size=(int)strlen(string);
    uint8_t md[bytes];
    keccak((uint8_t*)string, size, md, bytes);
    NSMutableString *sha3 = [[NSMutableString alloc] initWithCapacity:bitsLength/4];
    
    for(int32_t i=0;i<bytes;i++)
        [sha3 appendFormat:@"%02X", md[i]];
    return sha3;
}

#pragma mark SHA265加密 后台对key加密
- (NSString *)ddy_SHA256WithKey:(NSString *)key {
    const char *cKey  = [key  cStringUsingEncoding:NSASCIIStringEncoding];
    const char *cData = [self cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)];
    const unsigned char *buffer = (const unsigned char *)[HMACData bytes];
    NSMutableString *HMAC = [NSMutableString stringWithCapacity:HMACData.length * 2];
    for (int i = 0; i < HMACData.length; ++i){
        [HMAC appendFormat:@"%02x", buffer[i]];
    }
    return HMAC;
}

Sha3 Keccak 256 用到的文件,

keccak.h

#ifndef KECCAK_H
#define KECCAK_H

#include <stdint.h>
#include <string.h>

#ifndef KECCAK_ROUNDS
#define KECCAK_ROUNDS 24
#endif

#ifndef ROTL64
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
#endif

// compute a keccak hash (md) of given byte length from "in"
int keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen);

// update the state
void keccakf(uint64_t st[25], int norounds);

#endif

keccak.c

#include "keccak.h"

const uint64_t keccakf_rndc[24] = 
{
    0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
    0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
    0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
    0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
    0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
    0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 
    0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
    0x8000000000008080, 0x0000000080000001, 0x8000000080008008
};

const int keccakf_rotc[24] = 
{
    1,  3,  6,  10, 15, 21, 28, 36, 45, 55, 2,  14, 
    27, 41, 56, 8,  25, 43, 62, 18, 39, 61, 20, 44
};

const int keccakf_piln[24] = 
{
    10, 7,  11, 17, 18, 3, 5,  16, 8,  21, 24, 4, 
    15, 23, 19, 13, 12, 2, 20, 14, 22, 9,  6,  1 
};

// update the state with given number of rounds

void keccakf(uint64_t st[25], int rounds)
{
    int i, j, round;
    uint64_t t, bc[5];

    for (round = 0; round < rounds; round++) {

        // Theta
        for (i = 0; i < 5; i++)     
            bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20];

        for (i = 0; i < 5; i++) {
            t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1);
            for (j = 0; j < 25; j += 5)
                st[j + i] ^= t;
        }

        // Rho Pi
        t = st[1];
        for (i = 0; i < 24; i++) {
            j = keccakf_piln[i];
            bc[0] = st[j];
            st[j] = ROTL64(t, keccakf_rotc[i]);
            t = bc[0];
        }

        //  Chi
        for (j = 0; j < 25; j += 5) {
            for (i = 0; i < 5; i++)
                bc[i] = st[j + i];
            for (i = 0; i < 5; i++)
                st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5];
        }

        //  Iota
        st[0] ^= keccakf_rndc[round];
    }
}

// compute a keccak hash (md) of given byte length from "in"

int keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen)
{
    uint64_t st[25];    
    uint8_t temp[144];
    int i, rsiz, rsizw;

    rsiz = 200 - 2 * mdlen;
    rsizw = rsiz / 8;
    
    memset(st, 0, sizeof(st));

    for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) {
        for (i = 0; i < rsizw; i++)
            st[i] ^= ((uint64_t *) in)[i];
        keccakf(st, KECCAK_ROUNDS);
    }
    
    // last block and padding
    memcpy(temp, in, inlen);
    temp[inlen++] = 1;
    memset(temp + inlen, 0, rsiz - inlen);
    temp[rsiz - 1] |= 0x80;

    for (i = 0; i < rsizw; i++)
        st[i] ^= ((uint64_t *) temp)[i];

    keccakf(st, KECCAK_ROUNDS);

    memcpy(md, st, mdlen);

    return 0;
}

用下面的方式确保Objective-C语言的文件引用

#ifdef __OBJC__
// oc文件
#endif

121.不小心修改了系统SDK造成错误

cd ~/Library/Developer/Xcode/DerivedData/ModuleCache (删除该文件中的缓存即可)

122. VC中监听进入前后台

- (void)addObserverActive
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:)
                                                 name:UIApplicationWillResignActiveNotification object:nil]; //监听是否触发home键挂起程序.
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:)
                                                 name:UIApplicationDidBecomeActiveNotification object:nil]; //监听是否重新进入程序程序.
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    DDYInfoLog( @" Application did become active." );
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    DDYInfoLog( @" Application will resign active." );
}

123.系统相机修改按钮

-(UIView *)findView:(UIView *)aView withName:(NSString *)name{ 
Class cl = [aView class]; 
NSString *desc = [cl description]; 

if ([name isEqualToString:desc]) 
return aView; 

for (NSUInteger i = 0; i < [aView.subviews count]; i++) 
{ 
UIView *subView = [aView.subviews objectAtIndex:i]; 
subView = [self findView:subView withName:name]; 
if (subView) 
return subView; 
} 
return nil; 
}
-(void)addSomeElements:(UIViewController *)viewController{


UIView *PLCameraView=[self findView:viewController.view withName:@"PLCameraView"];
UIView *bottomBar=[self findView:PLCameraView withName:@"PLCropOverlayBottomBar"];
UIImageView *bottomBarImageForSave = [bottomBar.subviews objectAtIndex:0];
UIButton *retakeButton=[bottomBarImageForSave.subviews objectAtIndex:0]; 
[retakeButton setTitle:@"重拍" forState:UIControlStateNormal]; //左下角按钮
UIButton *useButton=[bottomBarImageForSave.subviews objectAtIndex:1]; 
[useButton setTitle:@"上传" forState:UIControlStateNormal]; //右下角按钮
}
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{

[self addSomeElements:viewController];
} 

123.监听横竖屏旋转,系统通知

UIDeviceOrientationDidChangeNotification

124.cocoapod search 不到绝对存在的库

rm ~/Library/Caches/CocoaPods/search_index.json 执行完重新 search 就行

125.iOS9 后UICollectionView header/footer 吸附悬停

// header
flowLayout.sectionHeadersPinToVisibleBounds = YES;
//footer
flowLayout.sectionFootersPinToVisibleBounds = YES;

UICollectionView的header悬停

126.判断触摸点是否在某个范围上

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    return YES;
}

127.scrollView(包括tableView,TextView,collectionView)滚动退键盘

scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;

128.tableView/CollectionView自适应高度(常用于嵌套)

[_collectionView performBatchUpdates:^{
        // 更新collection的约束一定要写在reload完成之前,否则会导致crash
    } completion:^(BOOL finished) {
        // 注意防止循环调用该方法
        CGFloat h = _collectionView.collectionViewLayout.collectionViewContentSize.height;
        // 不能超过某个临界值,这里不能超过屏幕高度
        _collectionView.ddy_h = h > DDYSCREENH ? DDYSCREENH : h;
    }];

129.延迟执行之坑

- (void)fireBlock:(dispatch_block_t)block {  
    block();  
}  
  
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
    [self performSelector:@selector(fireBlock:) withObject:^{  
        NSLog(@"hello world");  
    } afterDelay:0.3];  
}); 

上面的代码片段原有的目的是异步延迟0.3秒后输出Hello world。但是运行之后发现不会输出Hello world。
原因是:非主线程的NSRunLoop默认没有开启,而
-performSelector:withObject:afterDelay:;函数内部是通过NSTimer定时器实现,在NSRunLoop没有开启的情况下,NSTimer不会得到正常运行。

130.CABaseAnimation 按home键后台后切回前台动画停止解决

animation.removedOnCompletion = NO; 

131.监听挂起和重新进入程序

#pragma mark 监听挂起和重新进入程序
#pragma mark 添加监听
- (void)addObserverActive
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:)
                                                 name:UIApplicationWillResignActiveNotification object:nil]; //监听home键挂起.
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:)
                                                 name:UIApplicationDidBecomeActiveNotification object:nil];  //监听重新进入程序.
}

#pragma mark 进入前台
- (void)applicationDidBecomeActive:(UIApplication *)application
{
    DDYInfoLog( @"[LC_UIApplication] Application did become active." );
    _canInvite = YES;
}

#pragma mark 挂起程序
- (void)applicationWillResignActive:(UIApplication *)application
{
    DDYInfoLog( @"[LC_UIApplication] Application will resign active." );
    _canInvite = NO;
}

131.AVFoundation录制视屏返回后tabbar向下移动了20像素的解决

// 对应控制器设置

_cameraVC.modalPresentationStyle=UIModalPresentationOverFullScreen;

132. 音频播放中断后恢复播放

iOS8 前
遵循 AVAudioPlayerDelegate

- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player {
// 音频会话被中断。玩家将在这里暂停
}

- (void)audioPlayerEndInterruption:(AVAudioPlayer *)playerwithFlags:(NSUInteger)flags {
     if(flags== AVAudioSessionInterruptionFlags_ShouldResume&&player!= nil) {
       [player play];
}
} 
  当中断发生时,AVAudioPlayer 实例的 audioPlayerBeginInterruption: delegate 方法会被调用。这时,你的音频 session 已经被打断了。如果是来电,用户只能听到铃声。当通话结束或用户拒绝来电后,AVAudioPlayer 类的 udioPlayerEndInterruption:withFlags: delegate 方法会被调用。如果参数 withFlags 包含AVAudioSessionInterruptionFlags_ShouldResume 标识,你就可以用 AVAudioPlayer 的播放实例来立即恢复播放音频。

iOS8之后

// 注册打断通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(AVAudioSessionInterruptionNotification:) name:AVAudioSessionInterruptionNotification object:session];

然后实现方法

// 接收通知方法
- (void)AVAudioSessionInterruptionNotification: (NSNotification *)notificaiton {
    NSLog(@"%@", notificaiton.userInfo);
    
    AVAudioSessionInterruptionType type = [notificaiton.userInfo[AVAudioSessionInterruptionTypeKey] intValue];
    if (type == AVAudioSessionInterruptionTypeBegan) {
        [self.player pause];
    } else {
        [self.player play];
    }
}

133.NSTimer block形式(iOS 10 later)兼容iOS9 before

写个分类
NSTimer+DDYExtension.h

#import <Foundation/Foundation.h>

@interface NSTimer (DDYExtension)

+ (NSTimer *)ddy_scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block;

@end

NSTimer+DDYExtension.m

#import "NSTimer+DDYExtension.h"
#import <objc/runtime.h>

@implementation NSTimer (DDYExtension)

+ (void)load {
    // get orignal method
    Method orignalMethod = class_getInstanceMethod(self, @selector(scheduledTimerWithTimeInterval:repeats:block:));
    // get my method
    Method myMethod = class_getInstanceMethod(self, @selector(ddy_scheduledTimerWithTimeInterval:repeats:block:));
    // change
    method_exchangeImplementations(orignalMethod, myMethod);
}

+ (NSTimer *)ddy_scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block {
    if (@available(iOS 10.0, *)) {
        return [self scheduledTimerWithTimeInterval:interval repeats:repeats block:^(NSTimer * _Nonnull timer) { block(timer); }];
    } else {
        return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(ddy_timerInvoke:) userInfo:[block copy] repeats:repeats];
    }
}

+ (void)ddy_timerInvoke:(NSTimer *)timer {
    void (^block)(NSTimer *timer) = timer.userInfo;
    if (block) {
        block(timer);
    }
}

@end

然后正常调用+ scheduledTimerWithTimeInterval:repeats:block: 时内部实现了交换方法
或者用接口+ ddy_scheduledTimerWithTimeInterval:repeats:block:

134.label多行显示和Masonry自动布局

label.preferredMaxLayoutWidth = (WidthScreen - margin * 2);  
[label setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];  
label.numberOfLines = 0;  
[label mas_makeConstraints:^(MASConstraintMaker *make) {  
        make.top.left.right.mas_equalTo(self);  
        // 自适应label多行显示时,无需设置label高度  
        // make.height.mas_equalTo(40.0);  
}];

http://www.cnblogs.com/Camier-myNiuer/p/5589215.html

上一篇下一篇

猜你喜欢

热点阅读