本文对应github地址Tip001,如果由于github调整导致资源找不到,请访问github
0. 防止暴力点击
-
防止collection短时间点击多个item
[collectionView setUserInteractionEnabled:NO]; [collectionView performSelector:@selector(setUserInteractionEnabled:) withObject:[NSNumber numberWithBool:YES] afterDelay:0.05f];
-
防止短时间点击两个按钮
[view setExclusiveTouch:YES];
-
防止按钮短时间多次点击
- (void)todoSomething:(id)sender { // 在这里做真正的事情 } - (void)handleButtonClick:(UIButton *)sender { // 先将未到时间执行前的任务取消。 [[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(todoSomething:) object:sender]; [self performSelector:@selector(todoSomething:) withObject:sender afterDelay:0.2f]; }
1. 打印View根视图所有子视图
-
比如在 -viewDidAppear: 打断点,在控制台输入
po [self.view.superview recursiveDescription]
2. layoutSubviews调用时机
- 当视图第一次显示的时候会被调用
- 当这个视图显示到屏幕上了,点击按钮
- 添加子视图也会调用这个方法
- 当本视图的大小发生改变的时候是会调用的
- 当子视图的frame发生改变的时候是会调用的
- 当删除子视图的时候是会调用的
- layoutIfNeed
3. NSString去掉首尾某些字符
-
只针对首尾
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString: @", "]; NSString *newString = [trimString stringByTrimmingCharactersInSet:set];
4. CGAffineTransform属性
-
平移、旋转、缩放、复原
// 平移按钮 CGAffineTransform transForm = self.buttonView.transform; self.buttonView.transform = CGAffineTransformTranslate(transForm, 10, 0); // 旋转按钮 CGAffineTransform transForm = self.buttonView.transform; self.buttonView.transform = CGAffineTransformRotate(transForm, M_PI_4); // 缩放按钮 self.buttonView.transform = CGAffineTransformScale(transForm, 1.2, 1.2); // 初始化复位 self.buttonView.transform = CGAffineTransformIdentity;
5. 去掉分割线多余15像素
-
第一步: viewDidLayoutSubviews 添加
- (void)viewDidLayoutSubviews { if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) { [self.tableView setSeparatorInset:UIEdgeInsetsZero]; } if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) { [self.tableView setLayoutMargins:UIEdgeInsetsZero]; } }
-
第二步: 重写willDisplayCell方法
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { if ([cell respondsToSelector:@selector(setSeparatorInset:)]) { [cell setSeparatorInset:UIEdgeInsetsZero]; } if ([cell respondsToSelector:@selector(setLayoutMargins:)]) { [cell setLayoutMargins:UIEdgeInsetsZero]; } }
6. 计算方法耗时时间间隔
-
两个宏定义
#define TICK CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); #define TOCK NSLog(@"Time: %f", CFAbsoluteTimeGetCurrent() - start)
7. Color颜色宏定义
-
随机颜色
#define RANDOM_COLOR [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1]
-
颜色(RGBA)
#define DDYRGBA(r, g, b, a) [UIColor colorWithRed:(r)/255.0f green:(g)/255.0f blue:(b)/255.0f alpha:(a)]
8. UIAlertView
-
宏定义(不再建议用UIAlertView,推荐UIAlertController)
#define Alert(_S_, ...) [[[UIAlertView alloc] initWithTitle:@"提示" message:[NSString stringWithFormat:(_S_), ##__VA_ARGS__] delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil] show]
9. NSArray 快速求总和 最大值 最小值 和 平均值
-
利用相应keyPath
NSArray *array = [NSArray arrayWithObjects:@"2.0", @"2.3", @"3.0", @"4.0", @"10", nil]; CGFloat sum = [[array valueForKeyPath:@"@sum.floatValue"] floatValue]; CGFloat avg = [[array valueForKeyPath:@"@avg.floatValue"] floatValue]; CGFloat max =[[array valueForKeyPath:@"@max.floatValue"] floatValue]; CGFloat min =[[array valueForKeyPath:@"@min.floatValue"] floatValue]; NSLog(@"%f\n%f\n%f\n%f",sum,avg,max,min);
10. 修改Label中不同文字颜色
-
转成富文本(attributedText)
+ (__kindof NSMutableAttributedString *_Nonnull)changeTotalString:(NSString *_Nonnull)totalString subStringArray:(NSArray *_Nonnull)subStringArray subStringColor:(UIColor *_Nonnull)color andFont:(UIFont *_Nonnull)font { NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithString:totalString]; for (NSString *rangeStr in subStringArray) { NSRange range = [totalString rangeOfString:rangeStr options:NSBackwardsSearch]; [attributedStr addAttribute:NSForegroundColorAttributeName value:color range:range]; [attributedStr addAttribute:NSFontAttributeName value:font range:range]; } return attributedStr; }
11. 播放声音
-
需要引入AVFoundation
// 1.获取音效资源的路径 NSString *path = [[NSBundle mainBundle]pathForResource:@"sound" ofType:@"wav"]; // 2.将路径转化为url NSURL *tempUrl = [NSURL fileURLWithPath:path]; // 3.用转化成的url创建一个播放器 NSError *error = nil; AVAudioPlayer *player = [[AVAudioPlayer alloc]initWithContentsOfURL:tempUrl error:&error]; // 4.播放 [player play];
12. NSTimer
- NSTimer计算的时间并不精确
- NSTimer需要添加到runLoop运行才会执行,但是这个runLoop的线程必须是已经开启。
- NSTimer会对它的tagert进行retain,我们必须使用intvailte停止。target如果是self(控制器自己),那么VC的retainCount+1,如果你不释放NSTimer,那么你的VC就不会dealloc了,内存泄漏了。
13. Could not find Developer Disk Image
- 下载开发包
- 强制退出Xcode
- 前往"/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport"粘贴解压缩文件
14. UISearchBar 中cancel改成取消
-
如果层级改变可适当调整
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar { searchBar.showsCancelButton = YES; for(UIView *view in [[[searchBar subviews] objectAtIndex:0] subviews]) { if([view isKindOfClass:[NSClassFromString(@"UINavigationButton") class]]) { UIButton * cancel =(UIButton *)view; [cancel setTitle:@" 取消" forState:UIControlStateNormal]; } } return YES; }
15.截图功能
-
drawViewHierarchyInRect可截取导航(可以用window截图)
- (UIImage *)ddy_SnapshotImage { UIGraphicsBeginImageContext(self.bounds.size); if([self respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]){ [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO]; } else{ [self.layer renderInContext:UIGraphicsGetCurrentContext()]; } UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); NSData *imageData = UIImageJPEGRepresentation(image, 0.6); image = [UIImage imageWithData:imageData]; return image; }
我只是想要截个屏
附[view snapshotViewAfterScreenUpdates:YES];
16. 获取设备上所有app的bundle id
-
不知道现在还能不能用
import <objc/runtime.h> Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace"); NSObject* workspace = [LSApplicationWorkspace_class performSelector:@selector(defaultWorkspace)];NSLog(@"apps: %@", [workspace performSelector:@selector(allApplications)]);
17. iOS 判断图片类型
-
特征码
JPEG,JPG: 0xFF 0xD8 2字节 JPG是JPEG的缩写
BMP: 0x42 0x4D 2字节
PNG: 0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A 8字节
GIF: 0x47 0x49 0x46 0x38 0x39/ 0x37 0x61 GIF有87a和89a两种格式// 通过图片Data数据第一个字节 来获取图片扩展名 - (NSString *)contentTypeForImageData:(NSData *)data { uint8_t c; [data getBytes:&c length:1]; switch (c) { case 0xFF: return @"jpeg"; case 0x89: return @"png"; case 0x47: case 0x37: return @"gif"; case 0x49: case 0x4D: return @"tiff"; case 0x42: return @"bmp"; case 0x52: if ([data length] < 12) { return nil; } NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding]; if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) { return @"webp"; } return nil; } return nil; }
-
其实图片数据的第一个字节是固定的,一种类型的图片第一个字节就是它的标识, 我们来调用一下这个方法:
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:picPathStr]]; NSString *string = [self contentTypeForImageData:data];
18. App迭代开发版本号的规则介绍
- 1.修复Bug或者优化功能, 我们只修改叠加第三位数字, 其他不变,如1.0.1
- 2.有了新的需求, 在原基础上增加新功能, 版本号变为1.1.0, 清空第三位为0, 叠加第二位
- 3.需求功能大改, 更新量非常大, 那我们的版本号变为2.0.0, 需要叠加第一位, 清空其他为0
参考
19. iOS 系统权限介绍
20. 私有API实现进入后台(相当于按home键)
-
谨慎使用
[[UIApplication sharedApplication] performSelector:@selector(suspend)]; // suspend:暂停;
21. 带有中文的URL处理
-
URL编码
NSString *URLStr = @"http://static.tripbe.com/videofiles/视频/我的自拍视频.mp4"; // NSString *path = (__bridge_transfer NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL, (__bridge CFStringRef)URLStr, CFSTR(""), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)); NSString* encodedURLString = [URLStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
22. 给UIView/UILabel设置图片
使用UIImageView
[view setBackGroundColor:[UIColor colorWithPatternImage:img];
-
CALayer
view.layer.contents = (__bridge id)image.CGImage; // 设置显示的图片范围,四个值在0-1之间,对应的为x, y, w, h view.layer.contentsCenter = CGRectMake(0.25,0.25,0.5,0.5);
23. VC设置背景图片
-
见上 22
// 没必要添加UIImageView,直接在layer上画 self.view.layer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"beijing"].CGImage)
24. view的部分圆角问题
-
也可以自己设定路径
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view2.bounds byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight cornerRadii:CGSizeMake(10, 10)]; CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; maskLayer.frame = view2.bounds; maskLayer.path = maskPath.CGPath; view2.layer.mask = maskLayer; //其中, byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight /* 指定了需要成为圆角的角,用“|”组合。该参数是UIRectCorner类型的,可选的值有: * UIRectCornerTopLeft * UIRectCornerTopRight * UIRectCornerBottomLeft * UIRectCornerBottomRight * UIRectCornerAllCorners */
25.禁止程序运行时自动锁屏
-
一般用于视频播放
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
26. 常用删除命令
-
删库跑路,谨慎用之
# 清空废纸篓 sudo rm -rf ~/.Trash/ # 删除Xcode 编译的数据 rm -rf ~/Library/Developer/Xcode/DerivedData/ # 代码不提示删除 rm ~/Library/Caches/com.apple.dt.Xcode # pod search 搜不出真的存在的库 zsl 用自己的 rm /Users/zsl/Library/Caches/CocoaPods/search_index.json
27. 把tableview里cell的小对勾的颜色改成别的颜色
-
能自定义的最好自定义
tableView.tintColor = [UIColor redColor];
28. 修改textFieldplaceholder字体颜色和大小
[textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
[textField setValue:[UIFont boldSystemFontOfSize:16] forKeyPath:@"_placeholderLabel.font"];
29.主线程操作UI(对UI进行更新只能在主线程进行)
-
方法一
// waitUntilDone:是否线程任务完成执行 [self performSelectorOnMainThread:@selector(updateImage:) withObject:data waitUntilDone:YES];
-
方法二
dispatch_async(dispatch_get_main_queue(), ^{ //更新UI的代码,不用主线程中调用 });
-
方法三
// 使用NSOperationQueue // 第一种: [[NSOperationQueuemainQueue]addOperationWithBlock:^{ // do something }]; // 第二种:将工作内容封装在NSOperation中,然后 // [[NSOperationQueue mainQueue] addOperation:myOperation];
30. 两种方法删除NSUserDefaults所有记录
-
方法一
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier]; [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
-
方法二
- (void)resetDefaults { NSUserDefaults * defs = [NSUserDefaults standardUserDefaults]; NSDictionary * dict = [defs dictionaryRepresentation]; for (id key in dict) { [defs removeObjectForKey:key]; } [defs synchronize]; }
31. UITableView设置Section间距
-
注意有时候0就不生效了
// 只设一个可能仍出现20的高度,也不可设置0 // Header底部间距 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 40;//section头部高度 } // footer底部间距 - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { return 0.001; }
32.常用GCD总结
-
详见多线程部分
// 后台执行: dispatch_async(dispatch_get_global_queue(0, 0), ^{ // something }); // 主线程执行: dispatch_async(dispatch_get_main_queue(), ^{ // something }); // 一次性执行: static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // code to be executed once }); // 延迟2秒执行: dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // code to be executed after a specified delay });
33.tabBarController跳转到另一个一级页面
-
当我们用tabBarController时,若已经到其中一个TabBar的子页,又要跳转到某一个一级的页面时,如果这样写,导致底部出现黑边,引起tabbar消失的bug
[self.navigationController popToRootViewControllerAnimated:YES]; ((AppDelegate *)AppDelegateInstance).tabBarController.selectedIndex = 2;
-
解决方法一:删除动画
[self.navigationController popToRootViewControllerAnimated:NO]; ((AppDelegate *)AppDelegateInstance).tabBarController.selectedIndex = 2;
-
解决方法二:延迟执行另一个系统操作
[self.navigationController popToRootViewControllerAnimated:NO]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ ((AppDelegate *)AppDelegateInstance).tabBarController.selectedIndex = 2; });
34. UIWebView获取Html的标题title
titleLabel.text = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
35. user-Agent问题
-
AppDelegate 中 - (BOOL)application: didFinishLaunchingWithOptions:
NSDictionary *dict = @{@"UserAgent":@"appwebkit"}; [[NSUserDefaults standardUserDefaults] registerDefaults:dict];
-
应用
// 获取webView userAgent NSMutableString *userAgent = [NSMutableString stringWithString:[[UIWebView new] stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"]]; // 更改UserAgent NSString *newUagent = [NSString stringWithFormat:@"%@ WMall/%@", userAgent, [SystemInfo appShortVersion]]; NSDictionary *dictionnary = [[NSDictionary alloc] initWithObjectsAndKeys:newUagent, @"UserAgent", nil]; [[NSUserDefaults standardUserDefaults] registerDefaults:dictionnary];
-
考虑到兼容性,只对某些webview实施自定义UA。[这几个方法一定要是静态方法,要不然设置UA不生效]
NSString* defaultUserAgent = nil; #pragma mark 获取默认的UA,用于恢复UA + (void)initialize { if (self == [WebViewController class]) { defaultUserAgent = [[UIWebView new] stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"]; } } #pragma mark 在默认UA后追加自定义UA + (void)registeCustomizeWebViewUserAgent { UIDevice *device = [UIDevice currentDevice]; NSString *iOSName = [device systemName]; NSString *iOSVersion = [device systemVersion]; NSString *customizeUserAgent = [NSString stringWithFormat:@"xxxxxMobile/%@ (Platform/%@; %@/%@)", APP_SHORT_VERSION, @"iPad", iOSName, iOSVersion]; NSString *webViewUserAgent = [[UIWebView new] stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"]; customizeUserAgent = [webViewUserAgent stringByAppendingFormat:@" %@", customizeUserAgent]; if (customizeUserAgent) { [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"UserAgent": customizeUserAgent}]; } } - (void)dealloc { /*由于自定义的userAgent无法播放webview的视频,所以。当webview销毁的时候,重置一下userAgent*/ [[self class] recoverDefaultUserAgent]; } + (void) recoverDefaultUserAgent { if (defaultUserAgent) { [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"UserAgent": defaultUserAgent}]; } }
36. 汉字转为拼音
- (NSString *)Charactor:(NSString *)aString getFirstCharactor:(BOOL)isGetFirst {
// 转成了可变字符串
NSMutableString *str = [NSMutableString stringWithString:aString];
// 先转换为带声调的拼音
CFStringTransform((CFMutableStringRef)str,NULL, kCFStringTransformMandarinLatin,NO);
// 再转换为不带声调的拼音
CFStringTransform((CFMutableStringRef)str,NULL, kCFStringTransformMandarinLatin,NO);
CFStringTransform((CFMutableStringRef)str, NULL, kCFStringTransformStripDiacritics, NO);
NSString *pinYin = [str capitalizedString];
//转化为大写拼音
if(isGetFirst) {
// 获取并返回首字母
return [pinYin substringToIndex:1];
} else {
return pinYin;
}
}
37. 打印宏定义
-
优化release,防止打印
// 处于开发阶段 #ifdef DEBUG #define DDYLog(...) NSLog(__VA_ARGS__) //#define DDYInfoLog(fmt, ...) fprintf(stderr,"\nfunction:%s line:%d content:%s\n", __FUNCTION__, __LINE__, [NSString stringWithFormat:fmt, ##__VA_ARGS__] UTF8String]); #define DDYInfoLog(fmt, ...) {\ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];\ [dateFormatter setDateStyle:NSDateFormatterMediumStyle];\ [dateFormatter setTimeStyle:NSDateFormatterShortStyle];\ [dateFormatter setDateFormat:@"HH:mm:ss:SSS"]; \ NSString *str = [dateFormatter stringFromDate:[NSDate date]];\ fprintf(stderr,"[%s %s %d]: %s\n",[str UTF8String], [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [[NSString stringWithFormat:fmt, ##__VA_ARGS__] UTF8String]);\ } //#define DDYInfoLog(fmt, ...) NSLog((@"\n[fileName:%s]\n[methodName:%s]\n[lineNumber:%d]\n" fmt),__FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__) // 处于发布阶段 #else #define DDYLog(...) #define DDYInfoLog(...) #endif
38. CocoaPods
39. Runtime objc_msgSend报错
-
Too many arguments to function call ,expected 0,have3
Project --> Build Settings --> 搜索objc --> ENABLE_STRICT_OBJC_MSGSEND --> 设置NO
40. 3DTouch
41. 捕获系统外异常
void UncaughtExceptionHandler(NSException *exception) {
NSArray *callStackSymbols = [exception callStackSymbols];
NSString *callStackSymbolStr = [callStackSymbols componentsJoinedByString:@"\n"];
NSString *reason = [exception reason];
NSString *name = [exception name];
DDYInfoLog(@"异常名称:%@\n异常原因:%@\n堆栈标志:%@",name, reason, callStackSymbolStr);
}
- application: didFinishLaunchingWithOptions:
NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
42. Xcode Build Configuration
44. OC中语法糖
-
界限更鲜明
self.imageView = ({ UIImageView *imageView = [[UIImageView alloc] init]; imageView.image = [UIImage imageNamed:@"12345"]; imageView.frame = CGRectMake(0, 0, 100, 100); [self.view addSubview:imageView]; imageView; });
45.获取当前显示的控制器
-
能不用最好不用,能不在View中跳转最好别在View中跳转
+ (UIViewController *)findCurrentResponderViewController{ UIViewController *currentVC = nil; UIWindow *window = [[UIApplication sharedApplication] keyWindow]; 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]]) { currentVC = nextResponder; } else { UIViewController *topVC = window.rootViewController.presentedViewController; if (topVC) { currentVC = topVC; } else { currentVC = window.rootViewController; } } return currentVC; }
-
view中跳转
NASkillAptitudeVC *vc = [[NASkillAptitudeVC alloc] init]; [[self currentViewController].navigationController pushViewController:vc animated:YES]; - (UIViewController *)currentViewController { UIResponder *next = self.nextResponder; do { //判断响应者是否为视图控制器 if ([next isKindOfClass:[UIViewController class]]) { return (UIViewController *)next; } next = next.nextResponder; } while (next != nil); return nil; }
46. UIView虚线框
CAShapeLayer *borderLayer = [CAShapeLayer layer];
borderLayer.bounds = self.picView.frame;
borderLayer.position = self.picView.center;
borderLayer.path = [UIBezierPath bezierPathWithRoundedRect:borderLayer.bounds cornerRadius:3].CGPath;
borderLayer.lineWidth = 1;
borderLayer.lineDashPattern = @[@4, @2];
borderLayer.fillColor = [UIColor clearColor].CGColor;
borderLayer.strokeColor = [UIColor grayColor].CGColor;
[self.picView.layer addSublayer:borderLayer];
47. iOS打电话的三种方式对比
48. TableViewCell间距
- (void)setFrame:(CGRect)frame {
// 整体向下 移动10
frame.origin.y += 10;
// 间隔10
frame.size.height -= 10;
[super setFrame:frame];
}
49. 带UITableView的界面出现空白解决
-
酌情选择里面代码
- (void)deleteTopBlank { self.edgesForExtendedLayout = UIRectEdgeNone; self.navigationController.navigationBar.translucent = NO; self.automaticallyAdjustsScrollViewInsets = NO; self.extendedLayoutIncludesOpaqueBars = YES }