这些都是自己觉得非常宝贵的知识(也有踩过的坑),在此保存和分享一下
持续更新...
1.计算代码行数
find . -name "*.m" -or -name "*.h" -or -name "*.xib" -or -name "*.c" |xargs wc -l
2.防止滑动tableView时,定时器停止运行
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
3.iOS 判断app程序第一次启动方法
if(![[NSUserDefaults standardUserDefaults] boolForKey:@"firstStart"])
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"firstStart"];
NSLog(@"第一次启动");
}else{
NSLog(@"不是第一次启动");
}
4. cocoapods 版本管理
在 Podfile 或者 Cartfile 中指定依赖版本的时候我们可以看到类似这样的小飘箭头的符号,这代表版本兼容。比如兼容 2.6.1 表示高于 2.6.1 的 2.6.x 版本都可以使用,而 2.7 或以上不行;同理,如果兼容 2.6 的话,2.6,2.7,2.8 等等这些版本都是兼容的,而 3.0 不行。当然也可以使用 >= 或者是 = 这些符号。
5. fastlane
开发总是有趣的,但是发布一般都很无聊。因为发布流程每次都一样,非常机械。无非就是跑测试,打 tag,上传代码,写 release log,更新 podspec 等等。虽然简单,但是费时费力,容易出错。对于这种情景,自动化流程显然是最好的选择。而相比于自己写发布脚本,在 Cocoa 社区我们有更好的工具,那就是 fastlane。
fastlane 是一系列 Cocoa 开发的工具的集合,包括跑测试,打包 app,自动截图,管理 iTunes Connect 等等。
6.RunLoop 的运行状态
注册 RunLoopObserver 可以观测当前 RunLoop 的运行状态,并在状态机切换时收到通知:
- RunLoop开始
- RunLoop即将处理Timer
- RunLoop即将处理Source
- RunLoop即将进入休眠状态
- RunLoop即将从休眠状态被事件唤醒
- RunLoop退出
7.Autorelease对象什么时候释放?
这个问题拿来做面试题,问过很多人,没有几个能答对的。很多答案都是“当前作用域大括号结束时释放”,显然木有正确理解Autorelease机制。
在没有手加Autorelease Pool的情况下,Autorelease对象是在当前的runloop迭代结束时释放的,而它能够释放的原因是系统在每个runloop迭代中都加入了自动释放池Push和Pop
————Sunny 博客
8.CocoaPods pod install/pod update更新慢的问题
- pod install --verbose --no-repo-update
- pod update --verbose --no-repo-update
9.Object-C Category 和 Class Extension 的区别
Category
- 用于给class及其subclass添加新的方法
- 有自己单独的 .h 和 .m 文件
- 用于添加新方法,而不能添加新属性(property)
Class Extension
- Extension常被称为是匿名的Category
- 用于给类添加新方法,但只作用于原始类,不作用于subclass
- 只能对有implementation源代码的类写Extension,对于没有implementation源代码的类,比如framework class,是不可以的
- Extension可以给原始类添加新方法,以及新属性
10.URL 组成结构
NSURL *url = [NSURL URLWithString:@"http://www.onevcat.com/2011/11/debug/;param?p=307#more-307"];
NSLog(@"Scheme: %@", [url scheme]);
NSLog(@"Host: %@", [url host]);
NSLog(@"Port: %@", [url port]);
NSLog(@"Path: %@", [url path]);
NSLog(@"Relative path: %@", [url relativePath]);
NSLog(@"Path components as array: %@", [url pathComponents]);
NSLog(@"Parameter string: %@", [url parameterString]);
NSLog(@"Query: %@", [url query]);
NSLog(@"Fragment: %@", [url fragment]);
将url 转换为合法的url字符串
NSString *fixedStr = [reqStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
11.使label里的内容字体大小自适应label
descriptionLabel.adjustsFontSizeToFitWidth = YES;
12.用苹果自带MessageComposer 发送email/sms
developer.apple.com/library/ios…
调用 SMS
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"sms://800888"]];
若需要传递内容可以做如下操作:
加入:MessageUI.framework
#import <MessageUI/MFMessageComposeViewController.h>
实现代理:MFMessageComposeViewControllerDelegate
调用sendSMS函数
//内容,收件人列表
- (void)sendSMS:(NSString *)bodyOfMessage recipientList:(NSArray *)recipients
{
MFMessageComposeViewController *controller = [[[MFMessageComposeViewController alloc] init] autorelease];
if([MFMessageComposeViewController canSendText])
{
controller.body = bodyOfMessage;
controller.recipients = recipients;
controller.messageComposeDelegate = self;
[self presentModalViewController:controller animated:YES];
}
}
// 处理发送完的响应结果
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
[self dismissModalViewControllerAnimated:YES];
if (result == MessageComposeResultCancelled)
NSLog(@"Message cancelled")
else if (result == MessageComposeResultSent)
NSLog(@"Message sent")
else
NSLog(@"Message failed")
}
默认发送短信的界面为英文的,解决办法为: 在.xib 中的Localization添加一組chinese就ok了
13.测试跳转页面
#if 1
LoginViewController *vc = [[LoginViewController alloc] init];
_window.rootViewController = vc;
#else // 测试界面用
RegisterViewController *vc = [[RegisterViewController alloc] init];
_window.rootViewController = vc;
#endif
14.iOS系统中的蓝色色值
[UIColor colorWithRed:0.0 green:110.0/255.0 blue:1.0 alpha:1.0];
15.判断字符串汉字和字母的个数
- (CGFloat)inputString:(NSString *)string{
int x = 0;
int y = 0;
for (int i = 0; i < string.length; i++) {
NSRange range = NSMakeRange(i,1);
NSString *subString = [string substringWithRange:range];
const char *cString = [subString UTF8String];
if (strlen(cString) == 3)
{
NSLog(@"汉字");
x+=1;
}
else if(strlen(cString) == 1){
NSLog(@"字母");
y+=1;
}
}
return 10 + ([[NSString stringWithFormat:@"%lu",_selectRedAmount] length]+3+3*x+y)*5+10;
}
16.iOS 停靠模式
17.去掉UItableview headerview黏性
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView == _tableView)
{
CGFloat sectionHeaderHeight = SECTION_HEIGHT;
if (scrollView.contentOffset.y<=sectionHeaderHeight&&scrollView.contentOffset.y>=0) {
scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0);
} else if (scrollView.contentOffset.y>=sectionHeaderHeight) {
scrollView.contentInset = UIEdgeInsetsMake(-sectionHeaderHeight, 0, 0, 0);
}
}
}
18.合成两张图片为一张图片
- (UIImage *)addImage:(UIImage *)image1 toImage:(UIImage *)image2 {
UIGraphicsBeginImageContext(image1.size);
CGFloat width = image1.size.width;
CGFloat height = image1.size.height;
// Draw image1
[image1 drawInRect:CGRectMake(0, 0, image1.size.width, image1.size.height)];
// Draw image2
[image2 drawInRect:CGRectMake(width * 0.4, height * 0.4, width*0.2, height*0.2)];
UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resultingImage;
}
19.设置window alert等级以使其显示在状态栏之上
[_assetsCalendarWindow setWindowLevel:UIWindowLevelAlert];
iOS系统中定义了三个window层级,其中每一个层级又可以分好多子层级(从UIWindow的头文件中可以看到成员变量CGFloat _windowSublevel),不过系统并没有把这个属性开出来。UIWindow的默认级别是UIWindowLevelNormal,我们打印输出这三个level的值分别如下:
2012-03-27 22:46:08.752 UIViewSample[395:f803] Normal window level: 0.000000
2012-03-27 22:46:08.754 UIViewSample[395:f803] Alert window level: 2000.000000
2012-03-27 22:46:08.755 UIViewSample[395:f803] Status window level: 1000.000000
这样印证了他们级别的高低顺序从小到大为Normal < StatusBar < Alert
20.获取当前导航控制器下前一个控制器
- (UIViewController *)backViewController
{
NSInteger myIndex = [self.navigationController.viewControllers indexOfObject:self];
if ( myIndex != 0 && myIndex != NSNotFound ) {
return [self.navigationController.viewControllers objectAtIndex:myIndex-1];
} else {
return nil;
}
}
21.mac 使用终端连接后台,输出日志,查看验证码
cd /usr/local/tomcat-app/logs/
tail -1000f /usr/local/tomcat-app/logs/catalina.out
22.Xcode 8 运行一堆没用的logs解决办法

上图我们看到,自己新建的一个工程啥也没干就打印一堆烂七八糟的东西,这个应该是Xcode 8的问题,解决办法是设置OS_ACTIVITY_MODE : disable如下图:
23.升级Xcode8之后文字占用空间变化
创建一个Label然后让它自适应大小,字体大小都是17最后输出的宽度是不一样的,我们再看一下,下面的数据就知道为什么升级 iOS 10 之后App中有的文字显示不全了: 
英文字母会不会也有这种问题,我又通过测试,后来发现英文字母没有问题,只有汉字有问题。目前只有一个一个修改控件解决这个问题,暂时没有其他好办法来解决。
24.给tabbar添加点击动画
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
NSInteger index = [self.tabBar.items indexOfObject:item];
if (self.indexFlag != index) {
[self animationWithIndex:index];
}
}
// 动画
- (void)animationWithIndex:(NSInteger) index {
NSMutableArray * tabbarbuttonArray = [NSMutableArray array];
for (UIView *tabBarButton in self.tabBar.subviews) {
if ([tabBarButton isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
[tabbarbuttonArray addObject:tabBarButton];
}
}
CABasicAnimation*pulse = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
pulse.timingFunction= [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
pulse.duration = 0.08;
pulse.repeatCount= 1;
pulse.autoreverses= YES;
pulse.fromValue= [NSNumber numberWithFloat:0.7];
pulse.toValue= [NSNumber numberWithFloat:1.3];
[[tabbarbuttonArray[index] layer]
addAnimation:pulse forKey:nil];
self.indexFlag = index;
}
25.获取当前界面上显示的键盘UIKeyboard方法
正常情况下我们对iOS系统键盘的使用仅限于让其显示或者隐藏,不会有需要获取到它的对象,仅当有一种情况,即是当我们需要在界面上添加一些元素,并且希望这些元素能够不被键盘挡住。这种情况下我们需要找到当前键盘所在的Window,并将元素添加到这个Window上,如此一来,我们先要找到键盘的实例对象,它是UIView的子类对象,我们只需要调用其window方法就能找到包含了键盘的UIWindow对象,就可以进行元素的添加了。具体方法如下:
- (UIView *)findKeyboard
{
UIView *keyboardView = nil;
NSArray *windows = [[UIApplication sharedApplication] windows];
for (UIWindow *window in [windows reverseObjectEnumerator])//逆序效率更高,因为键盘总在上方
{
keyboardView = [self findKeyboardInView:window];
if (keyboardView)
{
return keyboardView;
}
}
return nil;
}
- (UIView *)findKeyboardInView:(UIView *)view
{
for (UIView *subView in [view subviews])
{
if (strstr(object_getClassName(subView), "UIKeyboard"))
{
return subView;
}
else
{
UIView *tempView = [FTEView findKeyboardInView:subView];
if (tempView)
{
return tempView;
}
}
}
return nil;
}
26.设置UILabel行间距
NSMutableAttributedString * attrString = [[NSMutableAttributedString alloc] initWithString:label.text];
NSMutableParagraphStyle * style = [[NSMutableParagraphStyle alloc] init];
[style setLineSpacing:20];
[attrString addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, label.text.length)];
label.attributedText = attrString;
27.在image上绘制文字并生成新的image
UIFont *font = [UIFont boldSystemFontOfSize:12];
UIGraphicsBeginImageContext(image.size);
[image drawInRect:CGRectMake(0,0,image.size.width,image.size.height)];
CGRect rect = CGRectMake(point.x, point.y, image.size.width, image.size.height);
[[UIColor whiteColor] set];
[text drawInRect:CGRectIntegral(rect) withFont:font];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
28.iPhone X 适配的宏定义
#define iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)
// 状态栏高度
#define STATUS_BAR_HEIGHT (iPhoneX ? 44.f : 20.f)
// 导航栏高度
#define NAVIGATION_BAR_HEIGHT (iPhoneX ? 88.f : 64.f)
// tabbar高度
#define TAB_BAR_HEIGHT (iPhoneX ? (49.f+34.f) : 49.f)
// home indicator
#define HOME_INDICATOR_HEIGHT (iPhoneX ? 34.f : 0.f)
29.使用YYLabel实现超链接效果
NSString *string = @"注册即表示同意《注册协议》和《隐私声明》";
NSMutableAttributedString * attrString = [[NSMutableAttributedString alloc] initWithString:string];
attrString.yy_font = [UIFont systemFontOfSize:12.0f];
attrString.yy_color = DEF_UICOLORFROMRGB(0x999999);
attrString.yy_underlineStyle = NSUnderlineStyleNone;
@weakify(self);
[attrString yy_setTextHighlightRange:[string rangeOfString:@"《注册协议》"]
color:DEF_UICOLORFROMRGB(0x0076FF)
backgroundColor:[UIColor clearColor]
tapAction:^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect){
@strongify(self);
[self registerProtocolButtonClicked:nil];
}];
[attrString yy_setTextHighlightRange:[string rangeOfString:@"《隐私声明》"]
color:DEF_UICOLORFROMRGB(0x0076FF)
backgroundColor:[UIColor clearColor]
tapAction:^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect){
@strongify(self);
[self privacyStatementButtonClicked:nil];
}];
_linkLabel = [[YYLabel alloc] init];
_linkLabel.frame = CGRectMake((DEF_DEVICE_WIDTH -290)/2, self.registerBtn.bottom +20, 290, 20);
_linkLabel.attributedText = attrString;
_linkLabel.textAlignment = NSTextAlignmentCenter;
_linkLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
_linkLabel.numberOfLines = 0;
_linkLabel.backgroundColor = [UIColor clearColor];
[self addSubview:_linkLabel];
30. 带有.00的数字,使用number类型json解析之后会失去精度
今天遇到了一个大坑,这个问题调查了很久。一直以为是jar包或者哪里转错了,自己动手实验了一下,发现是json js 和java数值范围不同引起的。
{
“boolean”: true,
“starttimeseconds”:9223372036854122112,
“null”: null,
“number”: 11222222222222222223,
}
上边是一段json格式的字符串,经由json编辑器转成json对象的结果是starttimeseconds:9223372036854122000;
造成这个现象的主要原因是 js 中的 number 数值类型是双浮点精度类型即 double , 而 java 中的 starttimeseconds 的类型为 long 类型, 也就是说 java 中得 long 能表示的范围比 js 中 number 大, 也就意味着部分数值在 js 中存不下, 所以在 js 中字符串转成 js 中的 object 的过程中数字精度发生额了丢失。
- 解决方法一:将starttimeseconds设置为string类型的,这个的话来回转换的 是字符串,不存在数值丢失。
- 解决方法二:protoful.js 的 long.js 解决。
31.进入某一页面,使某一输入框成为第一响应者,可能需要延迟
//键盘成为第一响应者,延迟展示(牢记)
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self.textField becomeFirstResponder];
}
//或者
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.textField becomeFirstResponder];
});