iOS常用技术
0.科学上网
npm config set registry https://registry.npm.taobao.org --global
npm config set disturl https://npm.taobao.org/dist --global
1.判断系统
#define UMSYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
调用方法:
UMSYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0") //高于或等于 iOS8.0的系统
2.关于导航控制器下的高度 (以后整理)
iOS 7 : viewDidLoad中 viewDidAppear:中
iOS 8及以后:viewDidLoad中 viewDidAppear:中
3.用逗号分隔一串数字
1 - (void)formatMoney{ 2 3 NSInteger moneyNum = 11111111232332; 4 5 NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; 6 7 formatter.numberStyle = NSNumberFormatterDecimalStyle; 8 9 NSString* formatMoney = [formatter stringFromNumber:[NSNumber numberWithInteger:moneyNum]]; 10 11 NSLog(@"%@",formatMoney); 12 13 }
4.nsdictionary的排序
1 // 按等级从小到大排序 2 3 NSArray *allKeys = [_dictLevelName allKeys]; 4 5 allKeys = [allKeys sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { 6 7 NSString *str1 = (NSString *)obj1; 8 9 NSString *str2 = (NSString *)obj2; 10 11 NSInteger level1 = [str1 integerValue]; 12 13 NSInteger level2 = [str2 integerValue]; 14 15 return [@(level1) compare:@(level2)]; // compare:是NSNumber 的函数,不可以比较字符串,需要单独转换. 16 17 }]; 18 19 for (NSString *key in allKeys) { 20 21 NSString *name = [_dictLevelName objectForKey:key]; 22 23 if (ISSTRING(name)) { 24 25 [_arrayLevelName addObject:name]; 26 27 } 28 29 }
5.NSAssert作用:若程序在此处崩溃,就能在不插入全局断点的情况下,崩在此处,代替全局断点的作用.
NSAssert(view, @"View must not be nil.");崩溃,倒退崩溃到了我的代码
[[PTVConfig instance] showToast:self.superview msg:@"解除屏蔽"];
是在 cell 中调用的,找不到父类 tableview 了,可见尽量少用 superview, 用父类作为代理直接处理.
6.查找最外层的控制器的方法:
UITabBarController *tabBar = (UITabBarController *)[[[[UIApplication sharedApplication] delegate] window] rootViewController];
UINavigationController *navi = tabBar.selectedViewController;
UIViewController *vc = navi.visibleViewController;
7.关于手势
- Tap(点一下)
- Pinch(二指往內或往外拨动,平时经常用到的缩放)
- Rotation(旋转)
- Swipe(滑动,快速移动)
- Pan (拖移,慢速移动)
- LongPress(长按)
8.运行 gif 图片,可以使用 UIImageView 动画. 代码如下:
1 - (void)test { 2 self.imgView.animationImages = [self animationImages]; //获取Gif图片列表 3 self.imgView.animationDuration = 1; //执行一次完整动画所需的时长 4 self.imgView.animationRepeatCount = 0; //动画重复次数 5 [self.imgView startAnimating]; 6 } 7 8 9 - (NSArray *)animationImages 10 { 11 NSFileManager *fielM = [NSFileManager defaultManager]; 12 NSString *path = [[NSBundle mainBundle] pathForResource:@"vip_new_comer_tail" ofType:@"bundle"]; 13 NSArray *arrays = [fielM contentsOfDirectoryAtPath:path error:nil]; 14 15 NSMutableArray *imagesArr = [NSMutableArray array]; 16 for (NSString *name in arrays) { 17 NSString *imagePath = [path stringByAppendingPathComponent:name]; 18 NSData *data = [NSData dataWithContentsOfFile:imagePath]; 19 UIImage *image = [UIImage imageWithData:data]; 20 if (image) { 21 [imagesArr addObject:image]; 22 } 23 } 24 return imagesArr; 25 }
9.对于字符串形式保存的用户配置,若将其转换成字典,可以先使用方法将其转换成 NSData 对象,再将该对象装换成 NSDictionary 对象.
1 NSString *conf = [dict objectForKey:@"conf"]; 2 if (conf) { 3 NSData * data = [conf dataUsingEncoding:NSUTF8StringEncoding]; 4 if (data) { 5 NSDictionary *confDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 6 } 7 }
10.若给父视图添加了手势,则子视图UIControl 的点击事件被触发后,会先执行父视图的手势,后执行按钮的事件.
若想阻碍父视图的按钮事件,安静地执行按钮事件,可以在手势的delegate的代理方法中,查看当前用户点击的视图,来确定是否调用父视图的代理方法.
1 - (void)viewDidLoad { 2 [super viewDidLoad]; 3 [self setupUI]; 4 } 5 6 - (void)setupUI{ 7 UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onViewTouchDonw:)]; 8 recognizer.delegate = self; 9 [self.view addGestureRecognizer:recognizer]; 10 11 [self.btn addTarget:self action:@selector(onBtnClick:) forControlEvents:UIControlEventTouchUpInside]; 12 } 13 14 -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch 15 { 16 if([touch.view isKindOfClass:[UIButton class]]) 17 { 18 NSLog(@"啦啦啦---%@",[touch.view class]); 19 20 return NO; 21 } 22 return YES; 23 }
11.判断麦克风和相机使用权限并打开的代码,iOS系统要在 plist 中添加信任的字符串,参考iOS 10 开发适配系列之权限Crash问题- 简书.
1 /// 检查相机和麦克风的访问权限并提示设置 2 - (BOOL)checkMediaTypeVideoAndAudio{ 3 BOOL bVideoAuthor = [self checkMediaTypeVideo]; 4 BOOL bAudioAuthor = [self checkMediaTypeAudio]; 5 6 if (bVideoAuthor && bAudioAuthor) { 7 return YES; 8 } else { 9 return NO; 10 } 11 } 12 13 /// 检查相机的访问权限并提示设置 14 - (BOOL)checkMediaTypeVideo{ 15 __block BOOL bAuthor = NO; 16 AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; 17 if (authStatus == AVAuthorizationStatusNotDetermined || 18 authStatus == AVAuthorizationStatusDenied ){ 19 20 // 首次访问照像机权限的时候会弹出允许或不允许的对话框,后来访问失败的话,会在以下 block 中传值为 NO 的参数 21 [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { 22 if (!granted) { 23 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:@"请在\"设置-隐私-相机\"选项中,允许熊猫直播访问你的相机" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil]; 24 [alertView show]; 25 } else { 26 bAuthor = YES; 27 } 28 }]; 29 } 30 return bAuthor; 31 } 32 33 /// 检查麦克风的访问权限并提示设置 34 - (BOOL)checkMediaTypeAudio{ 35 __block BOOL bAuthor = NO; 36 AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio]; 37 if (authStatus == AVAuthorizationStatusNotDetermined || 38 authStatus == AVAuthorizationStatusDenied ) { 39 40 // 首次访问麦克风权限的时候会弹出允许或不允许的对话框,后来访问失败的话,会在以下 block 中传值为 NO 的参数 41 [AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) { 42 if (!granted) { 43 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:@"请在\"设置-隐私-麦克风\"选项中,允许熊猫直播访问你的麦克风" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil]; 44 [alertView show]; 45 } 46 }]; 47 48 } 49 return bAuthor; 50 }
12.YYModel不同变量的使用方法
1 + (NSDictionary *)modelCustomPropertyMapper { 2 NSMutableDictionary *chatMappers = [@{@"text" : @"data.text", 3 @"color" : @"data.color", 4 @"size" : @"data.size", 5 @"font" : @"data.font", 6 } mutableCopy]; 7 NSDictionary *baseMappers = @{@"rid" : @"from.rid", 8 @"nick" : @"from.nick", 9 @"level" : @"from.level", 10 @"fromLevelMin" : @"from.level_min", 11 @"fromLevelMax" : @"from.level_max", 12 @"exp" : @"from.exp", 13 @"roleName" : @"from.role_name", 14 @"roleVal" : @"from.role_val", 15 @"xroomId" : @"to", 16 @"type" : @"type", 17 }; 18 [chatMappers addEntriesFromDictionary:baseMappers]; 19 return chatMappers; 20 }
13.YYText 在 cell 中时,获取点击的位置
1 - (void)onTapChatMsg:(UITapGestureRecognizer *)tap{ 2 CGRect rect = self.chatMsgLabel.textLayout.textBoundingRect; 3 CGPoint point = [tap locationInView:tap.view]; 4 if (CGRectContainsPoint(rect, point)) { 5 NSLog(@"被点击了"); 6 } 7 }
14.选中某个 cell 的常用代码:
1 /// 某个 cell 是否被选中, 在 cellForItemAtIndexPath 代理方法中调用 2 - (void)selectedCellIfNeeded:(PXYStickerCollectionViewCell *)cell indexPath:(NSIndexPath *)indexPath 3 { 4 if (self.lastSelectIndexPath == nil) 5 { 6 return; 7 } 8 if(indexPath.item == self.lastSelectIndexPath.item) 9 { 10 cell.backgroundColor = [UIColor colorWithRed:0.4 green:0.4 blue:0.4 alpha:0.4]; 11 cell.gradientLayer.hidden = YES; 12 } 13 else 14 { 15 cell.backgroundColor = [UIColor clearColor]; 16 cell.gradientLayer.hidden = NO; 17 } 18 } 19 20 /// 选中某个 cell, 在 didSelectItemAtIndexPath 代理方法中调用 21 - (void)selectingIndexPath:(NSIndexPath *)indexPath collectionView:(UICollectionView *)collectionView{ 22 23 PXYStickerCollectionViewCell *cell = (PXYStickerCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath]; 24 cell.backgroundColor = [UIColor colorWithRed:0.4 green:0.4 blue:0.4 alpha:0.4]; 25 cell.gradientLayer.hidden = YES; 26 27 if (self.lastSelectIndexPath == nil) 28 { 29 self.lastSelectIndexPath = indexPath; 30 return; 31 } 32 else if (self.lastSelectIndexPath.item == indexPath.item) 33 { 34 return; 35 } 36 37 PXYStickerCollectionViewCell *lastCell = (PXYStickerCollectionViewCell *)[collectionView cellForItemAtIndexPath:self.lastSelectIndexPath]; 38 lastCell.backgroundColor = [UIColor clearColor]; 39 lastCell.gradientLayer.hidden = NO; 40 self.lastSelectIndexPath = indexPath; 41 }
15.限制输入多少个字符
1 - (void)textViewDidChange:(UITextView *)textView{ 2 NSString *lang = [[UIApplication sharedApplication]textInputMode].primaryLanguage; // 键盘输入模式 3 if ([lang isEqualToString:@"zh-Hans"]) { // 简体中文输入,包括简体拼音,健体五笔,简体手写 4 UITextRange *selectedRange = [textView markedTextRange]; 5 //获取高亮部分 6 UITextPosition *position = [textView positionFromPosition:selectedRange.start offset:0]; 7 // 没有高亮选择的字,则对已输入的文字进行字数统计和限制 8 if (!position) { 9 [self checkTextViewText:textView]; 10 } 11 // 有高亮选择的字符串,则暂不对文字进行统计和限制 12 else{ 13 [self checkTextViewText:textView]; 14 } 15 } 16 // 中文输入法以外的直接对其统计限制即可,不考虑其他语种情况 17 else{ 18 19 } 20 } 21 22 - (void)textViewDidEndEditing:(UITextView *)textView{ 23 [self checkTextViewText:textView]; 24 } 25 26 - (void)checkTextViewText:(UITextView *)textView { 27 if (textView.text.length > kMaxInputWindPlaneEditView) { 28 textView.text = [textView.text substringToIndex:kMaxInputWindPlaneEditView]; 29 [[PTVConfig instance] showToast:self msg:[NSString stringWithFormat:@"文字长度不能超过%li个字符",(long)kMaxInputWindPlaneEditView]]; 30 } 31 }
16.把崩溃日志转化为具体的某一行(crash 崩溃)(参考http://www.jianshu.com/p/da186c14db0f)
(/Users/liuzhu/Library/Developer/Xcode/DerivedData/xxx-atouolfjhjicfrgglhmhmicssual/Build/Products 中含有 dsym 文件)
1 chmod +x symbolicatecrash 2 export DEVELOPER_DIR="/Applications/XCode.app/Contents/Developer" 3 ./symbolicatecrash 1460.crash PandaTV-ios.app.dSYM > Control_symbol.crash
(PS:Xcode7.3
symbolicatecrash路径
/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash)
17.在分类中添加属性,核心代码如下:
1 #import <objc/runtime.h> 2 @property (nonatomic,assign) CGFloat count; 3 4 -(void)setCount:(CGFloat)count{ 5 objc_setAssociatedObject(self, @selector(count), @(count), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 6 } 7 8 -(CGFloat)count{ 9 NSNumber *count = objc_getAssociatedObject(self, @selector(count)); 10 return count.floatValue; 11 }
18.若 UIScrollView 的尺寸随着其中的图片尺寸在变化,则可以设置UIViewController中的automaticallyAdjustsScrollViewInsets属性来让其不变
1 - (void)viewDidLoad { 2 [super viewDidLoad]; 3 [self setAutomaticallyAdjustsScrollViewInsets:NO]; 4 }