日常记录笔记
一,获取导航栏相关属性
- 获取包含导航栏的高度:
CGRect rectStatus = [[UIApplication sharedApplication] statusBarFrame];
CGRect rectNav = self.navigationController.navigationBar.frame;
CGFloat maxY = rectStatus.size.height+rectNav.size.height;
二,字符串相关
- 截取,判断
NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//1. 根据某个字符串截取成多个子串
NSArray *subA = [msg componentsSeparatedByString:@"hosten_lym"];
//2. 判断是否包含某个字符串
NSRange range1 = [msg rangeOfString:@"hosten_lym"];
if (range1.location != NSNotFound) {
NSLog(@"%@",msg);
}
//3. 替换指定的字符串
subS = [subS stringByReplacingOccurrencesOfString:@"str" withString:@"reStr"];
三, 关于可变数值或字典的一些事情
1,不可变使用 copy 属性防止数组被其他对象修改,可变必须使用 strong 或者 retain ,原因如下:
@property(nonatomic, copy) NSMutableArray *remoteVideoMutArray;
_remoteVideoMutArray = [[NSMutableArray alloc] init];
[self.remoteVideoMutArray addObject:dic];
这样做会导致一个崩溃,如图:
实际上使用copy属性后;这里实际上已经转为不可变的数组,再对其赋值,就会导致上述错误,原理如下:
@property(nonatomic, copy) NSMutableArray *remoteVideoMutArray;
_remoteVideoMutArray = [[[NSMutableArray alloc] init] copy];
[self.remoteVideoMutArray addObject:dic];
因此,可变必须使用 strong 或者 retain ;
20210411更新:这里其实是深copy和潜copy的问题
浅拷贝是指针copy会影响引用计数,不开辟内存空间,深copy是数据copy不会影响引用计数,开辟内存空间;
对象类型 | copy方式 | 结果 | copy类型 |
---|---|---|---|
mutable对象 | copy | 不可变 | 浅拷贝 |
mutable对象 | mutablecopy | 可变 | 深拷贝 |
immutable对象 | copy | 不可变 | 浅拷贝 |
immutable对象 | mutablecopy | 可变 | 深拷贝 |
即:copy 之后的返回的对象都是不可变,mutablecopy之后返回的对象都是可变
四.关于控制器那些事
- 获取window下rootVC
- (UIViewController *)getCurrentVC
{
UIViewController *result = nil;
UIWindow * window = ((AppDelegate*)SYS_DELEGATE).window;
if (window.windowLevel != UIWindowLevelNormal)
{
NSArray *windows = [[UIApplication sharedApplication] windows];
for(UIWindow * tmpWin in windows)
{
if (tmpWin.windowLevel == UIWindowLevelNormal)
{
window = tmpWin;
break;
}
}
}
UIView *frontView = [[window subviews] objectAtIndex:0];
id nextResponder = [frontView nextResponder];
if ([nextResponder isKindOfClass:[UIViewController class]])
result = nextResponder;
else
result = window.rootViewController;
return result;
}
- 根据rootVC获取最顶层的控制器:
- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController
{
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController *tabBarController = (UITabBarController *)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
} else if (rootViewController.presentedViewController) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
3:多个控制器(父子控制器)
- 一般可以直接在一个控制器中直接把其他控制器的view添加进去,但是这样会导致很多问题;
[self.view addSubview:vc.view];
- 父子控制器
- (void) showView{//显示子控制器的view
// 获取之前控制器的view
UIView *firstView;
if (self.contentView.subviews.count) {
firstView = self.contentView.subviews[0];
}
// 显示子控制器
UIViewController *vc = self.childViewControllers[sender.tag];
vc.view.frame = self.contentView.bounds;
[self.contentView addSubview:vc.view];
// 移除之前控制器的view
[firstView removeFromSuperview];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// 1.添加子控制器
[self setUpCreateAllChildViewController];
// 2.设置按钮标题
[self setUpButtonTitle];
}
- (void)setUpButtonTitle
{
NSUInteger count = self.titleView.subviews.count;
// 3
// 0 1 2
for (int i = 0; i < count; i++) {
UIButton *btn = self.titleView.subviews[i];
UIViewController *vc = self.childViewControllers[i];
//将控制器的标题设置给按钮
[btn setTitle:vc.title forState:UIControlStateNormal];
}
}
// 添加子控制器
- (void)setUpCreateAllChildViewController
{
// 社会
test1ViewController *societyVc = [[test1ViewController alloc] init];
societyVc.title = @"测试1";
[self addChildViewController:societyVc];
// 头条
test2ViewController *topLine = [[test2ViewController alloc] init];
topLine.title = @"头条";
[self addChildViewController:topLine];
// 热点
test3ViewController *hotVc = [[test3ViewController alloc] init];
hotVc.title = @"热点";
[self addChildViewController:hotVc];
}
优点:
1. 父子控制中的自控制器可以使用导航控制器的push方法
五,应用后台模式(录音):
1:info.plist配置:
2:audio设置:
//设置设备允许蓝牙
- (BOOL)prepareAudioSession {
// deactivate session
BOOL success = [[AVAudioSession sharedInstance] setActive:NO error: nil];
if (!success) {
NSLog(@"deactivationError");
}
// set audio session category AVAudioSessionCategoryPlayAndRecord options AVAudioSessionCategoryOptionAllowBluetooth
success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil];
if (!success) {
NSLog(@"setCategoryError");
}
// activate audio session
success = [[AVAudioSession sharedInstance] setActive:YES error: nil];
if (!success) {
NSLog(@"activationError");
}
return success;
}
3:设置后台点击状态栏跳转到应用
//应用支持远程事件
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
4:实现效果:
六,库的那些事
1:库体积太大
命令行执行:
strip -S -X RTCSDK.framework/RTCSDK
2: 查看库中所有符号表:
nm -a
七,环境配置
在mac下配置cocos2dx游戏引擎的android编译环境配置
1、打开terminal(终端)
2、cd ~ ( 进入当前用户的home目录)
3、open .bash_profile (打开.bash_profile文件)
4、直接更改弹出的.bash_profile文件内容
5、command + s 保存文件,然后关闭
6、在terminal(终端)中输入 source .bash_profile (使用刚才更新之后的内容)
八,关于dispatch_semaphore的使用
- 例子:
// We want a synchronous request so that we know that we've left the room on
// room server before we do any further work.
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
[NSURLConnection sendAsyncRequest:request
completionHandler:^(NSURLResponse *response, NSData *data, NSError *e) {
if (e) {
error = e;
}
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
- 简述: 信号量的具体做法是:当信号计数大于0时,每条进来的线程使计数减1,直到变为0,变为0后其他的线程将进不来,处于等待状态;执行完任务的线程释放信号,使计数加1,如此循环下去。
`dispatch_samaphore_t dispatch_semaphore_create(long value)`
传入的参数为long,输出一个dispatch_semaphore_t类型且值为value的信号量。
long dispatch_semaphore_signal(dispatch_semaphore_tdsema)
这个函数会使传入的信号量dsema的值加1
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout)
这个函数会使传入的信号量dsema的值减1;
九,UITableView
1. storyboard 自定义cell高度
//告诉tableView的真实高度是根据约束计算的
_tableView.rowHeight = UITableViewAutomaticDimension;
//设置估算高度
_tableView.estimatedRowHeight = 50;
2. tableView编辑模式
//cell 添加多个按钮
-(NSArray<UITableViewRowAction*>*)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewRowAction *action = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@"删除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
NSLog(@"=--------删除");
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewAutomaticDimension];
// [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
}];
UITableViewRowAction *visAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"关注" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
NSLog(@"=--------关注");
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
}];
visAction.backgroundColor = [UIColor blueColor];
UITableViewRowAction *cancleaction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"取消" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
NSLog(@"=--------关注");
}];
return @[action,visAction,cancleaction];
}
一些控制台命令
- 文件操作:
- 查找文件中特定字符串
命令1:grep “测试字符串” log.txt
作用:从log.txt中找出“测试字符串”的数据
命令2:grep -n “测试字符串” log.txt
作用:从log.txt中找出“测试字符串”位置的数据,并在前面加上行号
命令3:grep (-n) Hello * (是否加上行号)
作用:从当前目录下的所有文件中找出出现过Hello的文件
一些开发便捷工具
- Alfred 便携搜索
- XtraFinder
- iTerm2
- Go2Shell
callKit 遇到的问题
- 1.CXEndCallAction 结束报错(
Domain = com.apple.CallKit.error.requesttransaction Code = 4
)问题;
CallKit对于每一个VoIP应用都应该只能有一个CXProvider
和CXCallController
的实例对象;重复的实例化CXProvider,那么在后续的结束时候就会出现上述错误,因此对于callKit 使用一个单例的类来管理,同时用来确保只能有一个CXProvider
和CXCallController
实例;使用下列方式来更新CXProviderConfiguration
:[self.callKitProvider setConfiguration:configuration];
XCode 12 显示某一行代码是谁修改的
下面的步骤都是基于sourcetree ,也就是XCode里已经加入了git账户等设置;然后根据下述流程就能显示每一行代码是谁修改的了;
- 点击下图右上角箭头所指的图标
- 选中箭头所示选项
- 然后就可以愉快的定位是谁修改了哪一行代码了,效果如下
4. 命令行git命令定位 方法:
- 在文件所在的目录打开命令行输入
git blame -L 150,300 文件名.m
‘-L’ 可选参数 表示 要查看的行数范围
- 查看提交记录
git show comitid