iOS Tips,不用就会忘记

1.  LLDB调试打印

2. UIWebView设置UA

3. 预处理宏,Preprocessor Macros

4.  快捷键

5.  执行xcodebuild命令  不工作  xcodebuild not work ,  输出  Build settings from command line: 命令后停止。用Xcode打开后就可以执行 编译命令了。

6. iOS 8.3之后获取iOS状态栏上手机的信号强度和wifi信号强度Signal Strength 。上架appstore会被拒,混淆后不知道可不可以

7. 打印出程序启动过程中各个阶段所消耗的时间

8. shell 脚本 选择编译Xcode ,然后在终端或者编译机上执行脚本就好。用于Xcode切换

9. 调用系统相册、相机,发现是英文的标题“photos”,但是手机语言已经设置显示中文。

10. Autolayout 实现UILablel文字竖排

11. plist 文件的格式转换 二进制或者 xml

12.  brew的一些命令

13. CocoaPods 引入测试库

14. UIViewController 设置导航栏和标签栏不同 title 的问题

15.  VC 多层 push 后回到指定页面的几种方法

16. "互斥锁" 避免死锁

17.Debug Memory Graph 应用 检测内存泄漏

18. heap WeChat | egrep 'class_rw|COUNT' 查看 class_rw_t 消耗的内存

19. nm BUAdSDK | grep crash_handle_signal 查看 Mach-O 中是否包含 crash_handle_signal 符号

20. sudo killall -STOP -c usbd  iOS手机usb链接一断一连一断一连,执行该命令

21.otool -ov   输出Objective-C类结构及其定义的方法

22.  strings mach-o  在对象文件或者二进制文件中查找可打印的字符串

23. ```SwiftUI 用的 通过开启 AG 的相关环境变量(AG_PRINT_CYCLES=2 & AG_TRAP_CYCLES=1),我们可以获取更多信息并让其在发生循环处断言崩溃。``` 目前还不知道干啥用的

1. LLDB调试打印,断点一个UIPasteboard的所有方法

(lldb) p UIScreen.mainScreen.bounds
error: property 'bounds' not found on object of type 'id'
error: 1 errors parsing expression
(lldb) expr @import UIKit 
(lldb) p UIScreen.mainScreen.bounds
(CGRect) $1 = (origin = (x = 0, y = 0), size = (width = 414, height = 736))
(lldb) 

 断点一个UIPasteboard的所有方法可以用如下命令

breakpoint set -r '\[UIPasteboard .*\]$'
br list

用lldb指令 frame variable -R 或者fr v -R查看对象结构

2.UIWebView设置UA

@implementation lzxzWebViewUtility : NSObject

+ (id)uiWebDocumentView:(UIWebView *)webview
{
    NSString *str = @"_documentView";
    id documentView = [webview performSelector:NSSelectorFromString(str)];
    id coreWebView = [documentView performSelector :@selector(webView)];
    return coreWebView;
}

+(NSString *)langzuxiaoziUA:(UIWebView *)webview
{
    static NSString* lbUA=nil;
    
    NSString*  appUA=objc_msgSend([lzxzWebViewUtility uiWebDocumentView:webview], NSSelectorFromString(@"applicationNameForUserAgent"));

    if(lbUA == nil){
        lbUA=[[appUA stringByAppendingFormat:@" langzuxiaozi/%@",[lzxzUIGlobal appBuildNum]] retain];
    }
    return lbUA;
}

+ (void)changeWebview:(UIWebView *)webview UserAgent:(NSString*)strUA
{
    SEL sel = NSSelectorFromString(@"setApplicationNameForUserAgent:");

    [[lzxzWebViewUtility uiWebDocumentView:webview] performSelector:sel withObject:strUA];
}

@end

//获取到带langzuxiaozi字符的ua
NSString* strUA = [lzxzWebViewUtility langzuxiaoziUA:self.webView];
//设置webview自定义ua
[lzxzWebViewUtility changeWebview:self.webView UserAgent:strUA];

3.预处理宏,Preprocessor Macros

如果写一些打印日志,只希望在debug版本中打印,release版本中不打印,可以这么写

#ifdef DEBUG
    NSLog(@"%s",__func__);
#endif

这样程序在编译的时候,只有在debug版本中才会编译这段代码。DEBUG是由Xcode创建项目的时候自动添加的配置,位置在Project -> Build Settings -> Preprocessor Macros 的Debug中。

也可以自定义一些其他条目到debug或release中

4. 快捷键

项目之间切换 command + ~

.h和.m之间切换 control + command + ↑ or ↓

定位类文件 command + shift + J

类文件查找command+ shift + O

方法调用者查看 光标 放到函数名上 control+1 然后鼠标选Callers


5. 执行xcodebuild命令  不工作  xcodebuild not work ,  输出  Build settings from command line: 命令后停止。用Xcode打开后就可以执行 编译命令了。

xcodebuild clean build  -workspace osvideo.xcworkspace -configuration "Release" -scheme osvideo -archivePath /Users/ios/.hudson/jobs/Video.ly_test/workspace/build/archivefiles.xcarchive -sdk iphoneos archive


通过对比刚刚checkout 出的代码和 用Xcode打开后的代码的区别 发现在 projectName.xcworkspace projectName.xcodeproj 这中文件夹里有xcuserdata 文件夹,xcuserdata文件

夹里 有 username.xcuserdatad. 只要多了这个username.xcuserdatad文件夹,就能通过命令行编译。

解决办法是在 product -> scheme -> Manage Schemes 中的所有 scheme 右边的 Shared 全部选中。

这样后,重新checkkout 下来的代码就可以直接用命令行编译了

6.iOS 8.3之后获取iOS状态栏上手机的信号强度和wifi信号强度Signal Strength 。上架appstore会被拒,混淆后不知道可不可以

- (IBAction)btn:(id)sender {
    UIApplication *app = [UIApplication sharedApplication];
    NSArray *subviews = [[[app valueForKey:@"statusBar"]     valueForKey:@"foregroundView"] subviews];
    NSString *dataNetworkItemView = nil;
    NSString *dataSignalStrengthView = nil;
    for (id subview in subviews) {
        if([subview isKindOfClass:[NSClassFromString(@"UIStatusBarDataNetworkItemView") class]])
        {
            dataNetworkItemView = subview;
        }
        if([subview isKindOfClass:[NSClassFromString(@"UIStatusBarSignalStrengthItemView") class]]){
            dataSignalStrengthView = subview;
        }
    }
    if(dataNetworkItemView){
        int  wifiStrengthRaw =  [[dataNetworkItemView valueForKey:@"wifiStrengthRaw"] intValue];
        int  wifiStrengthBars =  [[dataNetworkItemView valueForKey:@"wifiStrengthBars"] intValue];
        int  dataNetworkType =  [[dataNetworkItemView valueForKey:@"dataNetworkType"] intValue];
        self.textView.text = [NSString stringWithFormat:@"wifiStrengthRaw = %d \nwifiStrengthBars = %d\n dataNetworkType = %d",wifiStrengthRaw,wifiStrengthBars,dataNetworkType];
    }else{
        self.textView.text = @"";
    }
    
    if(dataSignalStrengthView){
        
        int  signalStrengthRaw =  [[dataSignalStrengthView valueForKey:@"signalStrengthRaw"] intValue];
        int  signalStrengthBars =  [[dataSignalStrengthView valueForKey:@"signalStrengthBars"] intValue];
        self.textView.text = [NSString stringWithFormat:@"%@\nsignalStrengthRaw = %d\nsignalStrengthBars = %d",self.textView.text,signalStrengthRaw,signalStrengthBars];
    }
}

7. Edit Scheme ->Arguments -> Environment Variables 添加 DYLD_PRINT_STATISTICS = 1,

这样在调试时,可以在控制台打印出程序启动过程中各个阶段所消耗的时间。

8.shell 脚本 选择编译Xcode ,然后在终端或者编译机上执行脚本就好。用于Xcode切换

#!/bin/bash
echo 'pwd'|sudo -S xcode-select -s /Applications/Xcode7.3.1.app

9.调用系统相册、相机,发现是英文的标题“photos”,但是手机语言已经设置显示中文。

打开“info.plist”,添加一项“Localized resources can be mixed”,值设置为“yes”即可!

10.Autolayout 实现UILablel文字竖排

UILabel *label = [[UILabel alloc] init];
label.font = [UIFont systemFontOfSize:16];
label.preferredMaxLayoutWidth = label.font.pointSize;

不要设置UILabel宽度约束
 

11.plist 文件的格式转换 二进制或者 xml

plutil -convert binary1 /Users/wolf/code/Keyboard/keyboard_layout_standard_dvorak.plist -o inof.plist


这是转换成二进制文件.要转换成 xml 文件,就把 binary1 换成 xml

12. brew的一些命令

brew outdated          查看你的包是否需要更新
brew list --versions          查看你安装过的包列表
brew --version          查看brew版本
brew update          更新brew
brew upgrade          更新包(所有的)
brew upgrade swxftlint     更新某个包,比如swxftlint包
brew cleanup          清理旧版本的包缓存(Homebrew 将会把老版本的包缓存下来)

13.CocoaPods 引入测试库

通过 CocoaPods 引入的第三方库可以通过配置 configurations 选项让它们只在 Debug 下生效 

pod 'netfox', :configurations => ['Debug']

14.UIViewController 设置导航栏和标签栏不同 title 的问题

在一个 VC 中设置相关标题简单总结如下:

self.navigationItem.title: 设置 VC 顶部导航栏的标题

self.tabBarItem.title: 设置 VC 底部标签栏的标题

self.title: 同时修改上述两处的标题

参考文档
UIViewController.title 
https://developer.apple.com/documentation/uikit/uiviewcontroller/1621364-title?language=objc

15. VC 多层 push 后回到指定页面的几种方法

RootVC -- > A -- > B -- > C,然后现在要求C直接pop回到A。

方法一:C返回到B的时候写个回调,B接收到回调再自己pop到A,但是这个方法B的页面会闪现一下,用户体验不好,不推荐。

方法二:在B push 到C的时候,直接把B从导航控制器的堆栈中移除

C_ViewController *vc = [[C_ViewController alloc] init];
NSMutableArray *navArray = [[NSMutableArray alloc] initWithArray:self.navigationController.viewControllers];
[navArray replaceObjectAtIndex:[navArray count] - 1 withObject:vc];
[self.navigationController setViewControllers:navArray animated:YES];

方法三:写一个UIViewController的catrgory,方法实现如图二。在C的backAct方法中使用,如图三。有的同学可能会怀疑B会不会内存泄露,可以在B中打印dealloc。

- (void)backToController:(NSString*)ctrlClassName animated:(BOOL)animated{
    if (self.navigationController){
        NSArray *controllers = self.navigationController.viewControllers;
        NSArray *result = [controllers filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id  _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
            return [evaluatedObject isKindOfClass:NSClassFromString(ctrlClassName)];
        }]];
        if (result.count > 0){
            [self.navigationController popToViewController:result[0] animated:animated];
        }
    }
}
- (void)backAct{
    [self backToController:@"A_ViewController" animated:YES];
}

这里比较推荐方法三。不论有多少级的push,只要传入指定页面的类名,都能回到该页面。

16. "互斥锁" 避免死锁

看 YYMemoryCache.m 的源码.

pthread_mutex_t _lock;
pthread_mutex_init(&_lock, NULL);

BOOL finish = NO;
while (!finish) {
    if (pthread_mutex_trylock(&_lock) == 0) {
        if (_lru->_totalCount > countLimit) {
            _YYLinkedMapNode *node = [_lru removeTailNode];
            if (node) [holder addObject:node];
        } else {
            finish = YES;
        }
        pthread_mutex_unlock(&_lock);
    } else {
        usleep(10 * 1000); //10 ms
    }
}

pthread_mutex_destroy(&_lock);

重点是使用 pthread_mutex_trylock() 方法尝试获取锁,而获取失败过后做了一个线程睡眠操作usleep().

在老版本中用是自旋锁 OSSpinLock,后来由于OSSpinLock的 bug 问题(存在潜在的优先级反转BUG),作者将其替换成了pthread_mutex_t互斥锁。

互斥锁它有一个特性:当多个线程出现数据竞争时,除了“竞争成功”的那个线程外,其他线程都会空转一段时间后进入被动挂起状态,而当“竞争成功”的那个线程解锁时,会主动去将其他线程激活,这个过程包含了上下文的切换,cpu抢占,信号发送等开销,很明显,互斥锁的起始开销有些大,效率低于自旋锁.

pthread_mutex_trylock() 尝试获取锁,获取失败会立刻返回,不会空转然后被挂起.

在当前线程睡眠10毫秒,然后再次尝试获取锁.这么做多了线程切换的时间.效率下降了吧.

17. Debug Memory Graph 应用 检测内存泄漏

为了能看到内存详细信息,先打开 Edit Scheme-->Diagnostics, 勾选 Malloc Scribble 和 Malloc Stack。为了避免过多的性能消耗,在 Malloc Stack 中直接选择 Live Allocations Only 即可。

然后运行Xcode,点击三个圆圈的小按钮后,右边栏点击右上角的 Show the Memory Inspector,会有堆栈信息,并且能直接定位到内存泄漏的代码块

21.otool -ov 输出Objective-C类结构及其定义的方法

0000000103bb9100 0x1045abe10 _OBJC_CLASS_$_WeatherData
    isa        0x1045abe38 _OBJC_METACLASS_$_WeatherData
    superclass 0x0 _OBJC_CLASS_$_NSObject
    cache      0x0 __objc_empty_cache
    vtable     0x0
    isa        0x1045abe38 _OBJC_METACLASS_$_WeatherData
    superclass 0x0 _OBJC_CLASS_$_NSObject
    cache      0x0 __objc_empty_cache
    vtable     0x0
    data       0x103d81130 __OBJC_CLASS_RO_$_WeatherData
        flags          0x184 RO_HAS_CXX_STRUCTORS
        instanceStart  8
        instanceSize   408
        reserved       0x00000000
        ivarLayout     0x103935184
        layout map:    0x33 0x17 0x1f 0x0f 0x32
        name           0x103935178 WeatherData
        baseMethods    0x103d7fba0 __OBJC_$_INSTANCE_METHODS_WeatherData
            entsize 24
            count   119
            name    0x103771a5f init
            types   0x10395b692 @16@0:8
            imp     0x1009a48d4 -[WeatherData init]
            name    0x1037c4ff6 isExpired
            types   0x10395b6d7 B16@0:8
            imp     0x1009a49e8 -[WeatherData isExpired]
            name    0x1037e4027 isGPSExpired
            types   0x10395b6d7 B16@0:8
            imp     0x1009a4acc -[WeatherData isGPSExpired]
            name    0x103778381 sceneID
            types   0x10395b692 @16@0:8
            imp     0x1009a4bb0 -[WeatherData sceneID]

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值