iOS开发笔记

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";
修改toolbar上的Placeholder.png
xib中创建多个view属性连接如果出现问题就查看某一个view的连接情况
xib多个view属性连接问题.png
Unbalanced calls to begin/end appearance transitions for <MainViewController: 0x7ab61a20>.

原因就是上次动画还没结束,然后又开始了新的动画,导致下一个的页面无法顺利压栈,这个只需要上一个页面返回的时候不要做动画或就可以了。

解决方法
1:去掉上一个页面或当前界面动画
2:当前界面动画延迟
3:监听上一个界面或当前的动画是否完成
参考:http://sdlqhjk.iteye.com/blog/1769057

TableView点击状态栏滑动到顶部无效时如何处理

点击statusBartableView自动滑动到顶部的功能,其实这个功能系统已实现,是需要tableView.scrollsToTop = true即可,但是我们经常遇到一个viewController中多个scrollView和tableView的情况,这时要注意:

1、系统默认scrollsToTop属性是打开的,我们要将 除了想要具备自动滑动到顶部的视图的 其他视图的scrollsToTop属性全部关掉scrollsToTop = false,否则,全部视图的滑动到顶部的功能都将失效;
2、如果在一个父控制器中添加多个子控制器A,B,C ,想A控制器中的tableView实现自动滑动到顶部,则这时B,C控制器的tableViewscrollsToTop属性要 = false

真机调试不打印log问题解决

ios9以前的 如果不加图片的那句 在xcode8 会打印一些没用的日志 但是你的系统要是ios10 如果真机调试 加了这句就不会打印 要是删除了就能

21_467146_d145755f49bde09.png
显示和隐藏mac文件命令

显示隐藏文件

defaults write com.apple.finder AppleShowAllFiles -bool true

关闭显示隐藏文件

defaults write com.apple.finder AppleShowAllFiles -bool false
modal跳转

ApresentBpresentC
CdismissA 代码

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


xib设置按钮圆角.png
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,然后就可以提交了。

20140807144121479.png

http://blog.sina.com.cn/s/blog_5c91824f0102vdlr.html

修改光标颜色
textField.tintColor = [UIColor redColor];  
image在xcode中设置不被渲染
Image Set Render As.png
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时注意

cellselectionNone的时候,点击cell时内部的控件不会进入高亮状态,如textLabelhighlightedTextColor就会失效。当cellselectionDefault的时候,点击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值,默认是20height如果不设置,默认少20。

背景view拉伸

可以设置背景图片的slicingHorizontal and Vertical

Image Set-Slicing.png
Cell代码对属性访问的封装

在cell的setModel:中对访问属性的处理代码,放在modelget方法里。比如:

// .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的实现

如果同时重写了settergetter方法,是不会生成私有变量,需要手动添加。
如果声明为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取消任务

根据GETPOST的返回结果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颜色问题

如果设置了UINavigationBarappearance改变了导航栏按钮颜色,那么导航栏按钮的enabled=NO灰色就会失效,需要手动设置状态disable为灰色。此时如果在控制器的viewDidLoad里设置导航栏按钮enabledNO,不会生效,在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
imageMode.png
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里面的隐藏键盘功能
QQ20161020-0.png
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,如下图:

1013321-f9e9d7c60048d609.png

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • 概述在iOS开发中UITableView可以说是使用最广泛的控件,我们平时使用的软件中到处都可以看到它的影子,类似...
    liudhkk阅读 9,007评论 3 38
  • 越来越多的时间是在路上,步行,自行车,公交,汽车,火车,飞机。 现在的交通方便了,出行方式也多了,买张机票,南方到...
    有花有月阅读 137评论 0 0
  • 1 我看三月的眼神 就好象天空看着风筝 怀抱开阔只在无风的夜晚 我广博而盲目地爱着你啊 夜黑得伸手摸不见你的名字 ...
    李榆阅读 483评论 13 14
  • 我们总是在所有不是正确的时间找到自己的人生目标,在对的时间却遇不到合适的。 朋友小谢,是一个长相平凡,家境平凡,所...
    么么哒碰上萌萌哒阅读 315评论 0 0
  • 人生总是会发生什么事情是你想不到的,也许你的一句话就伤害了无辜的人,也许那时候你还不知道你犯的...
    久羁绊阅读 330评论 0 0