iOS XIB使用Safe Area后在iOS9和10上面出现的问题和解决方案
1.多添加一个距离SuperView的约束
2.设置这个约束为>=距离
3.设置距离Safe Area的约束优先级比距离SuperView约束优先级低。(比如750)
开发注意添加一个控制器的方法
// 缺一不可否则有可能会导致意外崩溃
[self addChildViewController:otherVC];
[self.view addSubview:otherVC.view];
UIButton禁用系统的高亮状态
[button setImage:[UIImage imageNamed:@"like"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:@"like"] forState: UIControlStateHighlighted];
[button setImage:[UIImage imageNamed:@"like_selected"] forState:UIControlStateSelected];
// 选中时候的高亮状态
[button setImage:[UIImage imageNamed:@"like_selected"] forState:UIControlStateSelected | UIControlStateHighlighted];
IQKeyboardManager修改toolbar上的Placeholder
#import "IQUIView+IQKeyboardToolbar.h"
textField3.placeholderText = @"This is the customised placeholder title for displaying as toolbar title";
xib中创建多个view属性连接如果出现问题就查看某一个view的连接情况
Unbalanced calls to begin/end appearance transitions for <MainViewController: 0x7ab61a20>.
原因就是上次动画还没结束,然后又开始了新的动画,导致下一个的页面无法顺利压栈,这个只需要上一个页面返回的时候不要做动画或就可以了。
解决方法
1:去掉上一个页面或当前界面动画
2:当前界面动画延迟
3:监听上一个界面或当前的动画是否完成
参考:http://sdlqhjk.iteye.com/blog/1769057
TableView点击状态栏滑动到顶部无效时如何处理
点击statusBar
,tableView
自动滑动到顶部的功能,其实这个功能系统已实现,是需要tableView.scrollsToTop = true
即可,但是我们经常遇到一个viewController中多个scrollView和tableView的情况,这时要注意:
1、系统默认
scrollsToTop
属性是打开的,我们要将 除了想要具备自动滑动到顶部的视图的 其他视图的scrollsToTop
属性全部关掉scrollsToTop = false
,否则,全部视图的滑动到顶部的功能都将失效;
2、如果在一个父控制器中添加多个子控制器A,B,C ,想A控制器中的tableView实现自动滑动到顶部,则这时B,C控制器的tableView
的scrollsToTo
p属性要= false
。
真机调试不打印log问题解决
ios9以前的 如果不加图片的那句 在xcode8 会打印一些没用的日志 但是你的系统要是ios10 如果真机调试 加了这句就不会打印 要是删除了就能
显示和隐藏mac文件命令
显示隐藏文件
defaults write com.apple.finder AppleShowAllFiles -bool true
关闭显示隐藏文件
defaults write com.apple.finder AppleShowAllFiles -bool false
modal跳转
Apresent
Bpresent
C
Cdismiss
A 代码
UIViewController *rootVC = self.presentingViewController;
while (rootVC.presentingViewController) {
rootVC = rootVC.presentingViewController;
}
[rootVC dismissViewControllerAnimated:YES completion:nil];
原理看这篇文章:http://www.jianshu.com/p/e2572e83071e
圆角按钮
代码方法:
btn.layer.cornerRadius = 8.0;
xib
DerivedData路径
/Users/xxx/Library/Developer/Xcode/DerivedData/
CornerStone静态库(.a文件)问题
首先打开软件左上角 CornerStone-Preferences-SubVersion
第一个地方把对号去掉,第二个地方把.a那个删除,然后save。
然后把你的.a文件放到本地的相应文件夹下,
但是 CornerStone(我的是v2.7.10 版本的) 里相应文件夹下看不到带问号的.a文件的话,点击上边 View-Show Ignored Items
到这里就ok了,选中你的静态库 点击底部Add 问号会变成A,然后就可以提交了。
http://blog.sina.com.cn/s/blog_5c91824f0102vdlr.html
修改光标颜色
textField.tintColor = [UIColor redColor];
image在xcode中设置不被渲染
appearance
UI_APPEARANCE_SELECTOR
凡是属性或方法后面有该宏标记的,都可以通过appearance
方法统一设置。
利用KVC修改系统的TabBar
[self setValue:customTabBar forKeyPath:@"tabBar"];
可以在自定义的- (void)layoutSubviews
中修改tabbar的frame。
分类中声明@property
在分类中声明@property, 只会生成方法的声明, 不会生成方法的实现和带有_下划线的成员变量
控制器title设置
self.title = @"标题";
// 相当于下面两句代码
self.navigationItem.title = @"标题"; // 设置导航栏标题
self.tabBarItem.title = @"标题"; // 设置tabbar标题
tabbarController添加控制器注意
不要在tabbarController里面访问子控制器的view,会导致提前创建view。
initialize
/**
* 当第一次使用这个类的时候会调用一次
*/
+ (void)initialize;
自己创建控制器xib
1.设置File's Owner
2.设置view
xib文字换行快捷键
option + return
Cell的selection为None时注意
当cell
的selection
为None
的时候,点击cell
时内部的控件不会进入高亮状态
,如textLabel
的highlightedTextColor
就会失效。当cell
的selection
为Default
的时候,点击cell
内部的控件会进入高亮状态
。
控制器销毁处理
当正在请求数据时还未请求回来,此时点击返回销毁控制器,如果请求回来的代码里访问了该控制器,会导致崩溃,解决方案是在dealloc
里取消请求。
- (void)dealloc {
// 取消请求
[self.manager.operationQueue cancelAllOperations];
}
利用runtime查找UITextField的隐藏成员变量
#import <objc/runtime.h>
+ (void)initialize {
unsigned int count = 0;
// 拷贝出所有的成员变量列表
Ivar *ivars = class_copyIvarList([UITextField class], &count);
for (int i = 0; i < count; i++) {
// 取出成员变量
Ivar ivar = ivars[i];
// 打印成员变量名字
NSLog(@"%s", ivar_getName(ivar));
}
// 释放
free(ivars);
}
textfield占位文字和光标颜色修改
修改占位文字颜色:
[self setValue:[UIColor grayColor] forKeyPath:@"_placeholderLabel.textColor"];
设置光标颜色和文字颜色一致:
self.tintColor = self.textColor;
button常用布局方法
[button layoutIfNeeded]; // 强制布局(强制更新子控件的frame)
[button.titleLabel sizeToFit]; // 让按钮内部的label根据文字内容来计算尺寸
关于viewWithTag的一点说明
用[父view viewWithTag:0]
取到的view
, 发现不是子view
, 而是这个父view
遇到这种情况就换一种思路取子view
,比如subViews
,或者把tag
值设置大一点
,防止误使用到苹果的保留tag。
tableView默认值
如果不给tableView
设置y
值,默认是20
,height
如果不设置,默认少20。
背景view拉伸
可以设置背景图片的slicing
为Horizontal and Vertical
Cell代码对属性访问的封装
在cell的setModel:
中对访问属性的处理代码,放在model
的get
方法里。比如:
// .m文件
#import "XMGTopic.h"
@implementation XMGTopic
- (NSString *)create_time
{
// 日期格式化类
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
// 设置日期格式(y:年,M:月,d:日,H:时,m:分,s:秒)
fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";
// 帖子的创建时间
NSDate *create = [fmt dateFromString:_create_time];
if (create.isThisYear) { // 今年
if (create.isToday) { // 今天
NSDateComponents *cmps = [[NSDate date] deltaFrom:create];
if (cmps.hour >= 1) { // 时间差距 >= 1小时
return [NSString stringWithFormat:@"%zd小时前", cmps.hour];
} else if (cmps.minute >= 1) { // 1小时 > 时间差距 >= 1分钟
return [NSString stringWithFormat:@"%zd分钟前", cmps.minute];
} else { // 1分钟 > 时间差距
return @"刚刚";
}
} else if (create.isYesterday) { // 昨天
fmt.dateFormat = @"昨天 HH:mm:ss";
return [fmt stringFromDate:create];
} else { // 其他
fmt.dateFormat = @"MM-dd HH:mm:ss";
return [fmt stringFromDate:create];
}
} else { // 非今年
return _create_time;
}
}
@end
MJExtension的使用
如果服务器返回的字段类型是int==0,1
,接收属性类型可以直接使用BOOL
setter和getter的实现
如果同时重写了setter
和getter
方法,是不会生成私有变量,需要手动添加。
如果声明为readonly
并重写了getter
方法,也不会生成私有变量。
设置frame和显示不一样
如果出现这种情况就添加下面代码
self.autoresizingMask = UIViewAutoresizingNone;
如果是在xib
中将控件添加到scrollView
中并没有设置约束
,用代码去设置frame是不行的,这时需要用代码添加到scrollView
如何知道图片的真实类型
就是取出图片数据的第一个字节
SDWebImage代码:
+ (NSString *)sd_contentTypeForImageData:(NSData *)data {
uint8_t c;
[data getBytes:&c length:1];
switch (c) {
case 0xFF:
return @"image/jpeg";
case 0x89:
return @"image/png";
case 0x47:
return @"image/gif";
case 0x49:
case 0x4D:
return @"image/tiff";
case 0x52:
// R as RIFF for WEBP
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 @"image/webp";
}
return nil;
}
return nil;
}
屏蔽第三方框架带来的风险
根据第三方框架包装一个自己的类,面向自己的类开发
reason:-[NSInvocation setArgument:atIndex:]:Index(2) out of bounds[-1,1]
selector参数有错误,比如将图片写入相册
// 错误
UIImageWriteToSavedPhotosAlbum(self.imageView.image, self, @selector(saveSuccess), nil);
// 正确
UIImageWriteToSavedPhotosAlbum(self.imageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
// 官方解释
// Adds a photo to the saved photos album. The optional completionSelector should have the form:
// - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;
UIKIT_EXTERN void UIImageWriteToSavedPhotosAlbum(UIImage *image, __nullable id completionTarget, __nullable SEL completionSelector, void * __nullable contextInfo) __TVOS_PROHIBITED;
pop和CoreAnimation的区别
pop:https://github.com/facebook/pop
- CoreAnimation的动画只能添加到layer上
- pop的动画可以添加到任何对象
- pop的底层并非基于CoreAnimation,而是基于CADisplayLink
- CoreAnimation的动画仅仅是表象,并不会修改对象的frame等值
- pop的动画会实时修改对象的属性,是真正的修改了对象的属性
modal控制器注意
modal控制器后面的控制器会暂时移出窗口
window使用注意
window如果不想设置主窗口,只是显示,只要hidden = NO
就出来了
windowLevel
级别:UIWindowLevelNormal
< UIWindowLevelStatusBar
< UIWindowLevelAlert
约束动画
- (void)keyboardWillChangeFrame:(NSNotification *)note
{
// 键盘显示\隐藏完毕的frame
CGRect frame = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
// 修改底部约束
self.bottomSapce.constant = XMGScreenH - frame.origin.y;
// 动画时间
CGFloat duration = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
// 动画 及时刷新
[UIView animateWithDuration:duration animations:^{
[self.view layoutIfNeeded];
}];
}
设置tableHeaderView的问题
设置tableHeaderView的时候,如果直接设置tableHeaderView为cell,且cell又重写了setFrame方法,且重写时候是这样的重写setFrame方法
,那么在拖tableView的时候系统会修改headerView的frame会一直调这个方法,就会出现问题。
解决方案:就是设置headerView为cell的时候外面包一层view就可以避免这个问题。
重写setFrame方法:
- (void)setFrame:(CGRect)frame
{
frame.origin.x = XMGTopicCellMargin;
frame.size.width -= 2 * XMGTopicCellMargin;
// frame.size.height -= XMGTopicCellMargin;
frame.size.height = self.topic.cellHeight - XMGTopicCellMargin;
frame.origin.y += XMGTopicCellMargin;
[super setFrame:frame];
}
设置tableHeaderView
- (void)setupHeader
{
// 创建header
UIView *header = [[UIView alloc] init];
// 清空top_cmt
if (self.topic.top_cmt.count) {
self.saved_top_cmt = self.topic.top_cmt;
self.topic.top_cmt = nil;
[self.topic setValue:@0 forKeyPath:@"cellHeight"];
}
// 添加cell
XMGTopicCell *cell = [XMGTopicCell cell];
cell.topic = self.topic;
cell.size = CGSizeMake(XMGScreenW, self.topic.cellHeight);
[header addSubview:cell];
// header的高度
header.height = self.topic.cellHeight + XMGTopicCellMargin;
// 设置header
self.tableView.tableHeaderView = header;
}
关于UIView的autoresizingMask属性
- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithReuseIdentifier:reuseIdentifier]) {
self.contentView.backgroundColor = XMGGlobalBg;
// 创建label
UILabel *label = [[UILabel alloc] init];
label.textColor = XMGRGBColor(67, 67, 67);
label.width = 200;
label.x = XMGTopicCellMargin;
label.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[self.contentView addSubview:label];
self.label = label;
}
return self;
}
UIViewAutoresizingNone 不自动调整。
UIViewAutoresizingFlexibleLeftMargin 自动调整与superView左边的距离,保证与superView右边的距离不变。
UIViewAutoresizingFlexibleRightMargin 自动调整与superView的右边距离,保证与superView左边的距离不变。
UIViewAutoresizingFlexibleTopMargin 自动调整与superView顶部的距离,保证与superView底部的距离不变。
UIViewAutoresizingFlexibleBottomMargin 自动调整与superView底部的距离,也就是说,与superView顶部的距离不变。
UIViewAutoresizingFlexibleWidth 自动调整自己的宽度,保证与superView左边和右边的距离不变。
UIViewAutoresizingFlexibleHeight 自动调整自己的高度,保证与superView顶部和底部的距离不变。
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin 自动调整与superView左边的距离,保证与左边的距离和右边的距离和原来距左边和右边的距离的比例不变。
MJExtension的映射
+ (NSDictionary *)replacedKeyFromPropertyName
{
return @{
@"small_image" : @"image0",
@"large_image" : @"image1",
@"middle_image" : @"image2",
@"ID" : @"id",
@"top_cmt" : @"top_cmt[0]" //,
// @"qzone_uid" : @"top_cmt[0].user.qzone_uid"
};
}
cell自动计算高度
IOS8的新特性“self-sizing”。
1. 要求cell.contentView的四条边都与内部元素有约束关系。
2. 添加这两行代码
self.tableView.estimatedRowHeight = 44.0f;
self.tableView.rowHeight = UITableViewAutomaticDimension;
补充:如果cell.contentView
里面还有其他内容代替显示自动伸缩的label
,比如一个按钮,且按钮高度为22,那么再给自动伸缩的label
添加一个约束label.height Greater than or equal 22
,此时cell就可正常显示。
AFNetworking取消任务
根据GET
或POST
的返回结果NSURLSessionDataTask
执行cancel
,执行后会回调失败block,也可以这么写
[self.manager.tasks makeObjectsPerformSelector:@selector(cancel)];
使用场景:
1.连续执行多个请求,只管最后一个,比如:上拉刷新后没请求回来就下拉刷新。
2.返回上个界面取消当前界面的所有请求,在dealloc方法里执行取消。
点击状态栏回到顶部
.h
文件
#import <Foundation/Foundation.h>
@interface XMGTopWindow : NSObject
+ (void)show;
+ (void)hide;
@end
.m
文件
#import "XMGTopWindow.h"
@implementation XMGTopWindow
static UIWindow *window_;
+ (void)initialize
{
window_ = [[UIWindow alloc] init];
window_.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 20);
window_.windowLevel = UIWindowLevelAlert;
[window_ addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(windowClick)]];
}
+ (void)show
{
window_.hidden = NO;
}
+ (void)hide
{
window_.hidden = YES;
}
/**
* 监听窗口点击
*/
+ (void)windowClick
{
UIWindow *window = [UIApplication sharedApplication].keyWindow;
[self searchScrollViewInView:window];
}
+ (void)searchScrollViewInView:(UIView *)superview
{
for (UIScrollView *subview in superview.subviews) {
// 主窗口
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
// 以主窗口左上角为坐标原点, 计算subview的矩形框
CGRect newFrame = [keyWindow convertRect:subview.frame fromView:subview.superview];
CGRect winBounds = keyWindow.bounds;
// 主窗口的bounds 和 subview的矩形框 是否有重叠
BOOL intersects = CGRectIntersectsRect(newFrame, winBounds);
BOOL isShowingOnKeyWindow = !subview.isHidden && subview.alpha > 0.01 && subview.window == keyWindow && intersects;
// 如果是scrollview, 滚动最顶部
if ([subview isKindOfClass:[UIScrollView class]] && isShowingOnKeyWindow) {
CGPoint offset = subview.contentOffset;
offset.y = - subview.contentInset.top;
[subview setContentOffset:offset animated:YES];
}
// 继续查找子控件
[self searchScrollViewInView:subview];
}
}
@end
注意:上面的代码会导致控制器中设置状态栏样式的代码失效,如下代码
/**
* 让当前控制器对应的状态栏是白色
*/
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
解决方案:
1.info.plist中添加View controller-based status bar appearance
,设置为NO
;
2.使用UIApplication设置:[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
注意:因为是全局设置在返回的时候要恢复原来的样式
监听tabbar的点击
AppDelegate.h
@interface AppDelegate () <UITabBarControllerDelegate>
@end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
XMGTabBarController *tabBarController = [[XMGTabBarController alloc] init];
tabBarController.delegate = self;
self.window.rootViewController = tabBarController;
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
// 发出一个通知
[XMGNoteCenter postNotificationName:XMGTabBarDidSelectNotification object:nil userInfo:nil];
}
给UIView设置背景图片
// 设置背景图片
- (void)drawRect:(CGRect)rect
{
[[UIImage imageNamed:@"mainCellBackground"] drawInRect:rect];
}
如果想重复调用drawRect
,调用[self setNeedsDisplay];
计算总行数
// 总行数 == (总个数 + 每行最大数 - 1) / 每行最大数
NSUInteger rows = (sqaures.count + maxCols - 1) / maxCols;
开发技巧
在xib中如果添加比如UIWebView、UIScrollView、UITableView
等控件被导航栏挡住,就将这些控件放在最顶部。
导航栏enable颜色问题
如果设置了UINavigationBar
的appearance
改变了导航栏按钮颜色,那么导航栏按钮的enabled=NO
灰色就会失效,需要手动设置状态disable
为灰色。此时如果在控制器的viewDidLoad
里设置导航栏按钮enabled
为NO
,不会生效,在viewDidAppear
里才会生效。若想在viewDidLoad
里生效,需要强制刷新。
- (void)viewDidLoad {
self.navigationItem.rightBarButtonItem.enabled = NO;
// 强制刷新
[self.navigationController.navigationBar layoutIfNeeded];
}
继承UIScrollView的view
任何继承自UIScrollView的view在添加到控制器后会自动增加64
的高度。注意一定要第一个添加。如果不想让系统自动增加,写下面代码
self.automaticallyAdjustsScrollViewInsets = NO;
setNeedsDisplay和setNeedsLayout
* setNeedsDisplay方法 : 会在恰当的时刻自动调用drawRect:方法
* setNeedsLayout方法 : 会在恰当的时刻调用layoutSubviews方法
presentedViewController
[a presentViewController:b animated:YES completion:nil];
a.presentedViewController -> b
b.presentingViewController -> a
判断输入框是否有文字
UITextField/UITextView
都可以使用hasText
方法判断。
监听键盘上的❌
继承自UITextField重写deleteBackward
- (void)deleteBackward {
!self.deleteBlock ? : self.deleteBlock();
[super deleteBackward];
}
快速取出数组中控件的属性值
vc.tags = [self.tagLabels valueForKeyPath:@"text"];
子控件布局问题
自定义view子控件的布局代码应该放在:
- (void)layoutSubviews {
[super layoutSubviews];
}
// 如需重新布局子控件调用
[self setNeedsLayout];
控制器中子控件的布局代码也应该放在:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
}
键盘问题
如果回到上个页面键盘不发出通知,就先退出键盘,在启用即可
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// 先退出之前的键盘
[self.view endEditing:YES];
// 再叫出键盘
[self.textView becomeFirstResponder];
}
自定义导航栏返回按钮失效
在自定义导航控制器中添加下面代码即可
- (void)viewDidLoad {
[super viewDidLoad];
// 如果滑动移除控制器的功能失效,清空代理(让导航控制器重新设置这个功能)
self.interactivePopGestureRecognizer.delegate = nil;
}
imageMode
UITabBar,移除顶部的阴影
[[UITabBar appearance] setShadowImage:[[UIImage alloc] init]];
[[UITabBar appearance] setBackgroundImage:[[UIImage alloc] init]];
NSDictionary 转 NSString
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parametersDic options:0 error:nil];
NSString *requestBody = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
设置Status bar颜色
如果没有navigation bar, 直接设置
self.view.backgroundColor = [UIColor lightGrayColor];
如果有navigation bar, 在navigation bar 添加一个view来设置颜色。
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, -20, ScreenWidth, 20)];
[view setBackgroundColor:[UIColor lightGrayColor]];
[viewController.navigationController.navigationBar addSubview:view];
使用AirDrop 进行分享:
NSArray *array = @[@"test1", @"test2"];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:array applicationActivities:nil];
[self presentViewController:activityVC animated:YES completion:^{
NSLog(@"Air");
}];
给UIView 设置透明度,不影响其他sub views
设置background color的颜色中的透明度
[self.testView setBackgroundColor:[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.5]];
//或
[self.testView setBackgroundColor:[[UIColor blackColor] colorWithAlphaComponent:0.5]];
给scrollview设置keyboardDismissMode实现Message app里面的隐藏键盘功能
instrument不能调试iOS8设备
解决:启用UI Automation,设置 -> 开发者 -> Enable UI Automation
http://stackoverflow.com/questions/24428197/xcode-6-with-ios-8-sdk-cant-run-ui-automation-in-instruments
崩溃:breakpoint 1.1
这个是程序运行的时候进断点了,把断点去掉就可以了
归档和反归档:
//创建
- (void)createSingleton {
//获得Document的路径
NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *pathString = [documents stringByAppendingPathComponent:path];//拓展名可以自己随便取
[NSKeyedArchiver archiveRootObject:self toFile:pathString];
}
//读取
- (CommonSingleton *)readSingleton {
NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *pathString = [documents stringByAppendingPathComponent:path];
CommonSingleton *singleton = [NSKeyedUnarchiver unarchiveObjectWithFile:pathString];
return singleton;
}
Cornerstone下载地址
Cornerstone3.0.3:http://soft.macx.cn/soft3947.htm
Cornerstone3.0.2:
http://bbs.feng.com/forum.php?mod=viewthread&tid=10810280&mobile=no
Cornerstone3.0:http://www.xp510.com/mac/30966.html
Cornerstone2.7.17:http://www.chinamac.com/download/mac53486.html
Cornerstone2.7.14:http://www.maczapp.com/cornerstone
Cornerstone2.7.10:http://bbs.feng.com/read-htm-tid-7936664.html
iOS项目代码行数统计
1、打开终端
2、cd 进入项目根目录
3、输入命令find . "(" -name "*.m" -or -name "*.mm" -or -name "*.cpp" -or -name "*.h" -or -name "*.rss" ")" -print | xargs wc -l
4、回车
精度计算原则
先转换为int计算,计算完后在转换为float,此时比较准确
Xcode8注释插件
(VVDocumenter)快捷键:option + command + /
Xcode8运行一堆没用的logs解决办法
设置OS_ACTIVITY_MODE : disable
,如下图:
Xcode dmg文件下载地址
https://developer.apple.com/download/more/
多用块枚举,少用for循环
NSDictionary *aDictionary = /* ... */;
[aDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop){
// Do something with 'key' and 'obj'
}];
这样做的好处是:在使用块进行快速枚举的时候,我们可以不创建临时数组。虽然语法上没有快速枚举简洁,但是我们可以获得数组元素对应的序号,字典元素对应的键值,而且,我们还可以随时令遍历终止。如果我们可以知道集合里的元素类型,就可以修改签名。这样做的好处是:可以让编译期检查该元素是否可以实现我们想调用的方法,如果不能实现,就做另外的处理。这样一来,程序就能变得更加安全。
访问实例变量注意
1.初始化方法和dealloc方法中,需要直接访问实例变量来进行设置属性操作。因为如果在这里没有绕过set方法,就有可能触发其他不必要的操作。
2.惰性初始化(lazy initialization)的属性,必须通过属性来读取数据。因为惰性初始化是通过重写get方法来初始化实例变量的,如果不通过属性来读取该实例变量,那么这个实例变量就永远不会被初始化。
支持http请求:
1 在Info.plist中添加NSAppTransportSecurity
类型Dictionary。
2 在NSAppTransportSecurity下添加NSAllowsArbitraryLoads
类型Boolean,值设为YES
不过从2017年1月1日起,,所有新提交的 app 默认不允许使用NSAllowsArbitraryLoads来绕过ATS的限制,默认情况下你的 app 可以访问加密足够强的(TLS V1.2以上)HTTPS内容;
3.可以选择使用NSExceptionDomains设置白名单的方式对特定的域名开放HTTP内容来通过审核,比如说你的应用集成了第三方的登录分享SDK,可以通过这种方式来做,下面以新浪SDK作为示范(Source Code 模式下):
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>sina.cn</key>
<dict>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.0</string>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
全能初始化方法
有时,由于要实现各种设计需求,一个类可以有多个创建实例的初始化方法。我们应该选定其中一个作为全能初始化方法,令其他初始化方法都来调用它。
AFN回调注意
AFN的成功失败回调代码已经在主线程了,所以不需要在代码块里写放在主线程中执行的代码。
AFN的成功失败代码块不需要使用weakSelf,因为造成循环引用的前提条件是控制器和代码块互相拥有,这里的AFN代码块不被控制器拥有,在控制器定义的block就会循环引用,这时候得使用weakSelf避免循环引用.
以“自动释放池快”降低内存峰值
内存峰值(high-memory waterline)是指应用程序在某个限定时段内的最大内存用量(highest memory footprint)。新增的自动释放池块可以减少这个峰值:
NSArray *databaseRecords = /* ... */;
NSMutableArray *people = [NSMutableArray new];
for (NSDictionary *record in databaseRecords) {
@autoreleasepool {
EOCPerson *person = [[EOCPerson alloc] initWithRecord:record];
[people addObject:person];
}
}
这样一来,每次循环结束,我们都会将临时对象放在这个池里面,而不是线程的主池里面。
插件路径
Xcode8:~/Library/Developer/Xcode/Plug-ins
Xcode8以前:~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/
iPhone各屏幕尺寸
机型 | 像素 | 屏幕尺寸 |
---|---|---|
iPhone4 | 640 x 960 | 320 x 480 |
iPhone5 | 640 x 1136 | 320 x 568 |
iPhone6 | 750 x 1334 | 375 x 667 |
iPhone6p | 1080x19201242 x 2208
|
414 x 736 |
有关屏幕的任何问题请查看链接:
http://blog.csdn.net/phunxm/article/details/42174937
推荐的开发笔记:
http://www.jianshu.com/p/d333cf6ae4b0#
http://www.cnblogs.com/yangmx/p/5631457.html