iOS一些小功能记录

从网上看到和平时用到一些iOS代码小功能记录下,方便后续查阅

----------------------------持续更新------------------------

1.UIView截图
- (UIImage *)getImageWithView:(UIView *)view {
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 0);

   //获取当前上下文
   CGContextRef ctx = UIGraphicsGetCurrentContext();
  //渲染
   [view.layer renderInContext:ctx];
   UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();
   return newImage;
}
//生成UIView形式的View
- (nullable UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates
2.UIView设置阴影
  • 设置为 masksToBounds=YES,阴影不显示;
  • 设置阴影时 view 的 frame 是否为 CGRectZero,如果是,设置阴影后修改 frame,也不会显示阴影;自动布局时 frame 为 CGRectZero 时,可以使用 layoutIfNeeded
  • 高效的阴影实现是为阴影指定 shadowPath
  //设置阴影颜色
    self.testView.layer.shadowColor = [UIColor blueColor].CGColor;
    //设置阴影透明度
    self.testView.layer.shadowOpacity = 0.8;
    //阴影圆角
    self.testView.layer.shadowRadius = 1;
    //设置阴影偏离位置
    self.testView.layer.shadowOffset = CGSizeMake(10, 2);
    
    UIEdgeInsets edges = UIEdgeInsetsMake(8, 10, 0, 0);
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(edges.left, edges.top, CGRectGetWidth(self.testView2.frame), CGRectGetHeight(self.testView2.frame))];
    //通过 shadowPath 设置阴影,可以自定义阴影的形状,这个方式可以避免离屏渲染
    self.testView2.layer.shadowPath = path.CGPath;
    self.testView2.layer.shadowColor = [UIColor blueColor].CGColor;
    //设置阴影透明度
    self.testView2.layer.shadowOpacity = 0.8;
    //阴影圆角
   self.testView2.layer.shadowRadius = 1;
3.设置圆角
  • 原生圆角效果带来的离屏渲染开销。直接使用圆角的素材,或者提前在子线程将图片进行圆角裁剪,
  • 还有一种思路是在需要圆角的视图最上层添加一个中空的圆角遮罩层,以此来做出圆角效果。这个遮罩层和被盖在下面的视图在显示时会由 GPU 进行图层混合,而图层混合的开销远小于离屏渲染
//给某个角度设置圆角 同样会触发离屏幕渲染
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.testView.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii:CGSizeMake(10, 10)];
 CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
 maskLayer.frame = self.testView.bounds;
 maskLayer.path = maskPath.CGPath;
 self.testView.layer.mask = maskLayer;
 //四个角设置圆角
 CAShapeLayer *mask = [CAShapeLayer new];
 mask.path = [UIBezierPath bezierPathWithRoundedRect:self.testView2.bounds cornerRadius:10].CGPath;
self.testView2.layer.mask = mask;

详细参考iOS设置圆角的四种方法

4.查看打印类的私有方法
  • _shortMethodDescription 可以显示所有接收者的实例和类方法

  • _methodDescription_shortMethodDescription一样, 包括父类的方法

  • _ivarDescription 可以显示 接收者的成员变量,包括类型和值

  • recursiveDescription 打印某个视图的层级关系

UIView *view = [[UIView alloc] init];
NSLog(@"_ivarDescription%@", [view  performSelector:@selector(_ivarDescription)]);
NSLog(@"_methodDescription =%@", [view performSelector:@selector(_methodDescription)]);
NSLog(@"_shortMethodDescription =%@", [view performSelector:@selector(_shortMethodDescription)]);

结果如图:


_ivarDescription

_shortMethodDescription

参考:
Extended Type Info in Objective-C
三个打印类信息的私有方法
Powerful private methods for debugging in Cycript & LLDB

5.iOS 9 以后通知不再需要手动移除
603C343F-CA1C-4C1C-93C7-65A4EDE43EFF.png

参考:
官方文档
iOS 9 以后通知不再需要手动移除

6.判断iPhone异形屏几种方式
  • 通过获取设备的device model来判断
  • 通过获取屏幕宽高来判断。(注意横竖屏)
  • 通过底部安全区域来判断
  if (@available(iOS 11, *)) {
        UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
        if (keyWindow == nil) {
            keyWindow = [[UIApplication sharedApplication] delegate].window;
        }
        CGFloat bottomSafeInset = keyWindow.safeAreaInsets.bottom;
        //竖屏34 横屏21.f
        if (bottomSafeInset == 34.f || bottomSafeInset == 21.f) {
            NSLog(@"我是异形屏");
        }
    }
//宏定义 判断是否是iPhone异形屏
#define  isIPhoneXSeries()\
^(){\
    BOOL iPhoneXSerie = NO;\
    if (UIDevice.currentDevice.userInterfaceIdiom != UIUserInterfaceIdiomPhone) {\
        return iPhoneXSerie;\
    }\
    if (@available(iOS 11.0, *)) {\
        UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];\
        if (mainWindow.safeAreaInsets.bottom > 0.0) {\
            iPhoneXSerie = YES;\
        }\
    }\
    return iPhoneXSerie;\
}()
  • 在设备处于竖屏且没有隐藏导航栏的时候,可以通过获取导航栏高度判断
 CGFloat statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
    if (statusBarHeight == 44.f) {
        NSLog(@"我是异形屏");
    }
  • 最后看到别人说的还可以通过判断是否支持FaceID判断,如果用户没有禁止使用的话。需要导入头文件<LocalAuthentication/LocalAuthentication.h>
   UIUserInterfaceIdiom idiom = [[UIDevice currentDevice] userInterfaceIdiom];
    if (idiom == UIUserInterfaceIdiomPhone) {
        if (@available(iOS 11, *)) {
            LAContext *laContext = [[LAContext alloc] init];
            if ([laContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:nil]) {
                if (laContext.biometryType == LABiometryTypeFaceID) {
                    NSLog(@"我是异形屏");
                }
            }
        }
    }
7.iOS9 以后字符串转换API

- (nullable NSString *)stringByApplyingTransform:(NSStringTransform)transform reverse:(BOOL)reverse API_AVAILABLE(macos(10.11), ios(9.0), watchos(2.0), tvos(9.0));
支持拼音繁体简体等转换。

    NSString *stringTest = @"我是一个测试";
    NSString * changeIntoPinYin = [stringTest stringByApplyingTransform:NSStringTransformToLatin reverse:NO];
    NSLog(@"汉字转拼音= %@",changeIntoPinYin);
    //去掉结合符号
    NSLog(@"去掉结合符号 = %@",[changeIntoPinYin stringByApplyingTransform:NSStringTransformStripCombiningMarks reverse:NO]);
    NSLog(@"简体转繁体= %@",[stringTest  stringByApplyingTransform:@"Hans-Hant" reverse:NO]);
打印结果

可参考
ICU Text Transforms in Foundation
Cocoa中的ICU文本转换
ICU - International Components for Unicode

8.为了防止遍历等其他的操作的时候内存压力过大,导致崩溃异常,可手动控制这些对象的生命周期,在适当的位置加上@autoreleasepool{}
9.使用runtime动态创建类

举个例子我这里创建一个继承FitfunBaseService的类。

#import <objc/runtime.h>

NSString * offlineApiBaseUrl(id self,SEL _cmd1){
    return objc_getAssociatedObject([self class], "apiServiceBaseUrl");
}


void createServiceClass(NSString *className,NSString *baseUrl) {
    const char * myClassName;
    myClassName = [className UTF8String];
    Class pClass = NSClassFromString(className);
    if (NSClassFromString(className) || NSClassFromString(@"FitfunBaseService") == nil) {
        return;
    }
    
    //创建类
    pClass = objc_allocateClassPair(NSClassFromString(@"FitfunBaseService"), myClassName, 0);
    objc_setAssociatedObject(pClass, "apiServiceBaseUrl", baseUrl, OBJC_ASSOCIATION_COPY);
    //为类创建方法
   class_addMethod(pClass, @selector(offlineApiBaseUrl), (IMP)offlineApiBaseUrl, "@@:");
    //注册类,使其能被引用。
    objc_registerClassPair(pClass);
}
10.runtime交换方法
void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector) {
   
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
    
    // 如果原有方法存在,添加就会失败
    BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    
    // 如果原有方法不存在添加一个方法
    if (didAddMethod) {
        class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    }
    else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
    
}

void swizzleMethodDifferentClasses(Class originalClass,Class swizzledClass, SEL originalSelector, SEL swizzledSelector) {
    //类方法交换
    Method originalMethod = class_getClassMethod(originalClass, originalSelector);
    Method swizzledMethod = class_getClassMethod(swizzledClass, swizzledSelector);
    method_exchangeImplementations(originalMethod, swizzledMethod);
}

11.除去数组重复元素

NSArray *oldArray = @[@"1",@"3",@"1",@{@"1":@"2"},@{@"1":@"2"},@{@"1":@"3"}];
NSArray *newArray = [oldArray valueForKeyPath:@"@distinctUnionOfObjects.self"];
NSLog(@"oldArray =%@,newArray =%@",oldArray, newArray);
//输出结果
oldArray =(
    1,
    3,
    1,
        {
        1 = 2;
    },
        {
        1 = 2;
    },
        {
        1 = 3;
    }
),newArray =(
    1,
    3
)

关于数组更多的kvc用法可参考高效开发iOS -- 那些不为人知的KVC

12.修改textField的placeholder的字体颜色、大小
[textField setValue:[UIColor greenColor] forKeyPath:@"_placeholderLabel.textColor"];
[textField setValue:[UIFont boldSystemFontOfSize:15] forKeyPath:@"_placeholderLabel.font"];
<==>等价
textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:
placeholder attributes:
@{NSFontAttributeName : [UIFont systemFontOfSize:15],
NSForegroundColorAttributeName : [UIColor  greenColor]}];
13.环境变量 DYLD_PRINT_STATISTICS打印出程序启动过程中各个阶段所消耗的时间,DYLD_PRINT_LIBRARIES (启动前和启动后的)和 DYLD_PRINT_LIBRARIES_POST_LAUNCH(启动后的),打印 dyld 加载的库

强调:DYLD_PRINT_STATISTICS 变量打印时间是iOS10以后才支持的功能,所以需要用iOS10系统及以上的机器来做测试。

配置环境变量

控制台打印结果

强烈推荐看iOS启动时间优化 ,讲的非常不错

14.更容易看懂宏

对于宏定义,可以使用xcode自带对单个文件预处理功能
Produce -> Perform Action -> Preprocess 'xxxx.m'

xcode操作

预处理后

预处理后
15.获取UIImage 图片的一部分
 UIImage *image = [UIImage imageNamed:@"test.png"];
 CGImageRef imageRef = image.CGImage;
 //这里xy和宽高相对于图片原始坐标来说来说的,比如我的图片现在宽高941x719,他的原始坐标就是(0,0,941,719)
 //取从图片从坐标(16,110)开始宽高都是290的局部
 CGRect imageRect = CGRectMake(160, 110, 290, 290);
 CGImageRef imageRectRef = CGImageCreateWithImageInRect(imageRef, imageRect);
 UIImage *newImage = [[UIImage alloc] initWithCGImage:imageRectRef];
 self.testImageView.image = newImage;
16.给UIView设置image
 UIImage *image = [UIImage imageNamed:@"test.png"];
 CGImageRef imageRef = image.CGImage;
 self.testView.layer.contents = (__bridge id)imageRef;
//设置拉伸范围
 self.testView.layer.contentsCenter = CGRectMake(0.8, 0.8, 1, 1);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容