iOS 开发经验总结

iOS 开发经验总结http://www.cocoachina.com/ios/20170216/18699.html

1.cocoa pods 常用的framework

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
platform :ios, '7.0'
 
target 'store' do
 
pod 'AFNetworking''~> 3.1.0'
pod 'JSONKit''~> 1.5pre'
pod 'MBProgressHUD''~> 0.9.2'
pod 'SDWebImage''~> 3.7.6'
pod 'SVPullToRefresh''~> 0.4.1'
pod 'JTObjectMapping''~> 1.1.2'
pod 'MagicalRecord''~> 2.3.2'
pod 'GetuiSDK''~> 1.4.2'
pod 'XTSafeCollection''~> 1.0.4'
pod 'libWeChatSDK''~> 1.6.2'
pod 'XMLDictionary''~> 1.4'
pod 'Masonry''~> 1.0.0'
pod 'OpenUDID''~> 1.0.0'
pod 'SAMKeychain''~> 1.5.0'
pod 'iVersion''~> 1.11.4'
pod 'iCloudDocumentSync''~> 7.4.1'
 
end

2.NSInteger打印以及字符串的转换

使用%zd打印NSInteger, %tu打印NSUInteger。

1
2
3
4
5
NSInteger integer = 1;
NSLog(@"first number: %zd", integer);
 
NSUInteger uinteger = 1;
NSLog(@"second number: %tu", uinteger);

3.UIScrollView 在iOS7中使用了Autolayout 导致不能滚动

1
2
3
- (void)viewDidLayoutSubviews
{
     [_mainScrollView setContentSize:CGSizeMake(SCREEN_WIDTH, SCREEN_HEIGHT + 10)];//增加10个像素让scrollview可上下滑动}

添加scrollView的content高度.

4.APP包瘦身

1)删除项目中没有使用的图片。 查找XCode工程中没被使用的图片资源

2)删除项目中没有用到的class 和 xib 及storyboard。分析工程中没有用到class

安装 fui 工具
sudo gem install fui -n /usr/local/bin

fui usage: https://github.com/dblock/fui

到工程目录下,执行 fui find 命令,可以找出所有的没有用到的class文件。

3)分析ipa包,找出大于500K的文件或内容 使用

1
find . -type f -size +500000c | xargs ls -lh

iOS 开发经验总结

图形搜索法

5.直接iOS7的连续跳转

1
2
3
4
5
6
7
- (void)back
{
    [self dismissViewControllerAnimated:YES
                             completion:^{                                 if (self.loginCanceled) {                                     self.loginCanceled();                                     self.loginCanceled = nil;
                                 }
                             }];
}

其中loginCanceled的实现

1
[weakSelf.navigationController popViewControllerAnimated:YES];

6.去除Preferred Max 的警告

警告的原因:

  • xib或storyboard中添加了UILabel的控件

  • UILabel的number lines 大于1

  • UILabel的preferred max没有设置值( @property(nonatomic) CGFloat preferredMaxLayoutWidth NS_AVAILABLE_IOS(6_0);)

解决方法:
1)如果是Storyboard的,右键点击警告

iOS 开发经验总结

警告

2)查看警告的详情

iOS 开发经验总结

详情

3)复制ID的值在搜索框中进行搜索

iOS 开发经验总结

搜索

4)点击搜索到的Label,可以找到label

iOS 开发经验总结

找到Label

5)设置preferred width为0,并选中explicit

iOS 开发经验总结

设置

6)警告解决

如果警告的是Xib,直接点击警告

iOS 开发经验总结

xib

就会跳转到对应的UILabel控件,设置preferred width为0,并选中explicit。 警告解决。

7.Cocoa pods更新到1.0 不能用了

更新完cocoa pods后,执行pod install后提示
Errno::ENOTEMPTY - Directory not empty @ dir_s_rmdir - /Users/arthurwang/SVN///*/Pods

[!] Oh no, an error occurred.Search for existing GitHub issues similar to yours:https://github.com/CocoaPods/CocoaPods/search?q=Directory+not+empty+%40+dir_s_rmdir+-+%2FUsers%2Farthurwang%2FSVN%2F59Store%2Fstoreapp-ios%2Fstore%2FPods&type=IssuesIf none exists, create a ticket, with the template displayed above, on:https://github.com/CocoaPods/CocoaPods/issues/newBe sure to first read the contributing guide for details on how to properly submit a ticket:https://github.com/CocoaPods/CocoaPods/blob/master/CONTRIBUTING.md
Don't forget to anonymize any private data!

解决方法:

删除项目中的Pods文件夹,再进行pod install的安装

8.interactivepopgesturerecognizer 使用

设置left bar button后,会导致右滑返回的效果失效,查看完美的设置方案。

同时为了获取到右滑返回的事件,可以执行
[self.navigationController.interactivePopGestureRecognizer addTarget:self action:@selector(back)];

在ViewController中viewDidAppare中添加,在viewWillDisappear中remove。

9.更新Cocoapods上的代码

1)采用私有的Cocoapods管理代码,需要添加

pod repo add HXSpec git@code.59store.com:ios/HXSpecs.git

将私有的Spec管理Git添加到pod的specs中。为了方便更新私有库。

2)在使用Cocoapods管理代码的时候,如果在GitHut上更新了代码,希望在project中执行pod install 来刷新代码,那么需要删除Pods和Podfile.lock文件

然后在执行pod install 来刷新代码

使用pod update进行repo的更新(更新私有库)

3)多次安装pod install 会出现Build Phase里多个Check Pods Manifest.lock的选项,这些选项可以删除。

采用直接将specs文件放到HXSpecs的管理库中,那么需要执行pod update 进行
Updating local specs repositories
不然会报错

4)删除这个目录下的缓存文件,进行第三方库文件的重新获取

/Users/arthurwang/Library/Caches/CocoaPods/Pods

5)进行两个组件相互依赖的时候,会导致报错:

[!] There is a circular dependency between StoreLocation and StoreBase

10. UICollectionView的数据不够,无法滑动——解决方案

tableView的数据无论多少,它的界面默认都是可以滑动的。
和tableView相比,当collectionView的数据较少不够一个屏幕时,它无法滑动。
解决方案:

1
_collectionView.alwaysBounceVertical = YES;

设置为总能垂直滑动就OK了。

11.MLeaksFinder 检查内存泄露

MLeaksFinder 直接用Pod导入就可以。根据DEBUG这个宏,开启内存泄露的检查,如果发现内存泄露,将断言。 So Good

12.删除String的中文

思路: 采用删除不用需要保留的字符,来实现删除中文的目的

1
2
3
4
5
6
7
//数字和字母
#define ALPHANUM @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
//数字
#define NUM @"0123456789"
 
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ALPHANUM] invertedSet];
NSString *filteredStr = [[textStr componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];

另外:UITextField 只能输入数字和字母

1
2
3
4
[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(textFieldChanged:)
                                                 name:UITextFieldTextDidChangeNotification
                                               object:nil];

监听name:UITextFieldTextDidChangeNotification 和 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

一起使用,来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (BOOL)validatePasswordString:(NSString *)resultMStr
{
 
    BOOL result = YES;
    switch (self.mode) {
        case HXSChangePasswordLogin: {
            NSString *regex = @"^[a-zA-Z0-9]+$";
            NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
            result = [pred evaluateWithObject:resultMStr];
            break;
        }
 
        case HXSChangePasswordPay: {
            NSString *regex = @"^[0-9]+$";
            NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
            result = [pred evaluateWithObject:resultMStr];
            break;
        }
    }
 
    return result;
}

13.iOS8 以后用WKWebView替代UIWebView

iOS8 之前使用UIWebView进行html的展示,使用UIWebView存在内存占用过大并不释放的问题。

WKWebView解决了内存占用过大的问题。

14.Xib中UILabel换行

在Xib中输入很长的文字,需要根据编号进行换行时,按“Enter”键无效。

方法:将文字在Text编辑工具编写好,copy到UILabel上。换行就有了

15.workspace — project — targets 讲解

一个工作空间可以包含多个项目,一个项目可以包含多个目标(生成物)。

一个项目中根据运行的targets不同,可以进行不同的编译设置,project是基础父类,targets是子类,targets的设置会覆盖project的设置。

16.绘画虚线, drawRect绘画frame未定的情况

1
2
3
[yourView.layer setBorderWidth:5.0];
[yourView.layer setBorderColor:
[[UIColor colorWithPatternImage:[UIImage imageNamed:@"DotedImage.png"]] CGColor]];//just add image name and create image with dashed or doted drawing and add here

这里只需要添加QuartzCore/QuartzCore.h框架,像下面一样导入.m文件:

iOS 开发经验总结

注意:
当使用Autolayout后,绘画虚线是根据frame进行的,那么在

1
2
3
4
- (void)drawRect:(CGRect)rect
{
    [self drawBorderLayer];
}

drawRect方法中,进行绘画。

17.Array 的深复制

指针的复制
dataArray3=[dataArray2 mutableCopy];
知识对dataArray2 进行了深复制,数组中的内容仅仅是指针的复制。

单层深复制
dataArray3=[[NSMutableArray alloc]initWithArray:dataArray2 copyItems:YES];
dataArray2进行本身和内容的深复制。单仅仅是内容的第一层

完全深复制
dataArray3 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:dataArray2]];
不管多少层都可以进行了深复制

18.企业证书下载版本可在APP中直接打开

在APP中有H5的页面,可以直接点击进行其他应用的下载

19.URL中对“#”的处理

1
2
3
4
NSString *str = @"http://test.fd.com/#/dte{}|||?lsfj=12&sdlfj=34&hao=你好";       
NSURL *url = [NSURL URLWithString:[str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"`%^{}"[]|\<> "].invertedSet]];
 
NSLog(@"url is %@", url);

输出: http://test.fd.com/#/dte%7B%7D%7C%7C%7C?lsfj=12&sdlfj=34&hao=%E4%BD%A0%E5%A5%BD

# 没有被转义
iOS9版本中需要使用 
stringByAddingPercentEncodingWithAllowedCharacters替代之前stringByAddingPercentEscapesUsingEncoding。

1
2
3
4
5
6
7
8
9
10
11
12
NSString *str = @"http://test.fd.com/#/dte{}|||?lsfj=12&sdlfj=34&hao=你好";       
NSURL *url = [NSURL URLWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSLog(@"[url scheme] is %@.", [url scheme]);
NSLog(@"[url host] is %@.", [url host]);
NSLog(@"[url password] is %@.", [url password]);
NSLog(@"[url user] is %@.", [url user]);
NSLog(@"[url path] is %@.", [url path]);
NSLog(@"[url query] is %@.", [url query]);
NSLog(@"[url fragment] is %@.", [url fragment]);
NSLog(@"[url resourceSpecifier] is %@.", [url resourceSpecifier]);
NSLog(@"[url parameterString] is %@.", [url parameterString]);
NSLog(@"[url relativePath] is %@.", [url relativePath]);

输出:
2016-08-09 18:57:52.913 store[20150:672790] [url scheme] is http.
2016-08-09 18:57:52.913 store[20150:672790] [url host] is test.fd.com.
2016-08-09 18:57:52.914 store[20150:672790] [url password] is (null).
2016-08-09 18:57:52.914 store[20150:672790] [url user] is (null).
2016-08-09 18:57:52.914 store[20150:672790] [url path] is /#/dte{}|||.
2016-08-09 18:57:52.914 store[20150:672790] [url query] is lsfj=12&sdlfj=34&hao=%E4%BD%A0%E5%A5%BD.
2016-08-09 18:57:52.914 store[20150:672790] [url fragment] is (null).
2016-08-09 18:57:52.915 store[20150:672790] [url resourceSpecifier] is //test.fd.com/%23/dte%7B%7D%7C%7C%7C?lsfj=12&sdlfj=34&hao=%E4%BD%A0%E5%A5%BD.
2016-08-09 18:57:52.915 store[20150:672790] [url parameterString] is (null).
2016-08-09 18:57:52.915 store[20150:672790] [url relativePath] is /#/dte{}|||.

20.APP 启动页不更新

修改了LaunchScreen.xib 后,模拟器上显示正常,但是真机上没有更新。

原因: 应用缓存

解决:真机上删除APP,重启手机,重新安装APP。

21. httpsdns 使用

申请 account id 下载sdk

查看SDK 文档 初始化,替换域名为IP

https://help.aliyun.com/document_detail/30116.html?spm=5176.product30100.4.28.bLXrJ4

在阿里云 里配置域名

22.打印不出变量的值 都显示nil

当对某个变量进行调试的并打印值时,一直返回nil。但是界面又能显示内容。

原因:说明这个变量是在某个线程中,而调试的不在这个线程里。

23.判断是否为gif/png图片的正确姿势

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//通过图片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:
            return @"gif";
 
        case 0x49:
        case 0x4D:
            return @"tiff";
 
        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;
}

其实图片数据的第一个字节是固定的,一种类型的图片第一个字节就是它的标识, 我们来调用一下这个方法:

1
2
3
4
5
6
7
//假设这是一个网络获取的URL
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:path]];
//调用获取图片扩展名
NSString *string = [self contentTypeForImageData:data];
//输出结果为 png
NSLog(@"%@",string);

24.JSPatch 的convertor 工具使用

左边输入

1
2
3
4
5
6
7
8
@implementation HXSAdTableViewCell
+ (CGFloat)getCellHeightWithObject:(HXSStoreAppEntryEntity *)storeAppEntryEntity
{
    CGFloat scale = [storeAppEntryEntity.imageHeightIntNum floatValue]/[storeAppEntryEntity.imageWidthIntNum floatValue];
     
    return ([UIScreen mainScreen].bounds.size.width) / 3 * scale + 30;
}
@end

右边输出

1
2
3
4
5
6
7
8
require('UIScreen');
defineClass('HXSAdTableViewCell', {} {
getCellHeightWithObject: function(storeAppEntryEntity) {
    var scale = storeAppEntryEntity.imageHeightIntNum().floatValue() / storeAppEntryEntity.imageWidthIntNum().floatValue();
     
    return (UIScreen.mainScreen().bounds().size().width()) / 3 * scale + 30;
},
});

有一个BUG: defineClass('HXSAdTableViewCell', {} { 在{}后面少一个“,”。

正确:

1
2
3
4
5
6
7
8
require('UIScreen');
defineClass('HXSAdTableViewCell', {}, {
getCellHeightWithObject: function(storeAppEntryEntity) {
    var scale = storeAppEntryEntity.imageHeightIntNum() / storeAppEntryEntity.imageWidthIntNum();
     
    return (UIScreen.mainScreen().bounds().width) / 3 * scale + 30;
},
});

25.Navigation bar的left bar button 跳动

1
2
3
4
5
6
7
- (void)jumpToViewController:(UIViewController *)vc
{
    // show the navigation bar in other vcs
    [self.navigationController setNavigationBarHidden:NO];
     
    [self.navigationController pushViewController:vc animated:YES];
}

当设置了 self.navigationItem.leftBarButtonItem.imageInsets = self.navigationController.viewControllers.count == 1 ? UIEdgeInsetsZero : UIEdgeInsetsMake(0, -5, 0, 5);

那么进行显示navigation bar的时候,就引起left bar button的跳动。

可以设置navigation bar hidden在push之前来解决。

26.Xcode8 出现ubsystem: com.apple.UIKit, category: HIDEventFiltered。。。的日志

解决办法:【product】-【scheme】-【Edit Scheme】-【Run】-【Argument】-【Environment Variable】添加keyValue【OS_ACTIVITY_MODE disable】可以停止输出打印此日志

27.intrinsic size 同一行有2个可变长度的的UILabel

Content Hugging Priority代表控件拒绝拉伸的优先级。优先级越高,控件会越不容易被拉伸。

而下面的Content Compression Resistance Priority代表控件拒绝压缩内置空间的优先级。优先级越高,控件的内置空间会越不容易被压缩

设置Content Hugging Priority 和 Content Compression Resistance Priority, 可实现当2个UILabel的内容都很长的时候,哪个label进行压缩,哪个Label进行显示完整。

28.pusher 推送测试

https://github.com/noodlewerk/NWPusher/releases/tag/0.7.0

直接进行推送的测试。

29.float的精度解决

将NSNumber转化为CGFloat时,精度失真。

1
2
3
4
5
6
7
8
9
NSString *decimalNumberMutiplyWithString(NSString *multiplierValue,NSString *multiplicandValue)
{
    NSDecimalNumber *multiplierNumber = [NSDecimalNumber decimalNumberWithString:multiplierValue];
    NSDecimalNumber *multiplicandNumber = [NSDecimalNumber decimalNumberWithString:multiplicandValue];
    NSDecimalNumber *product = [multiplicandNumber decimalNumberByMultiplyingBy:multiplierNumber];
    return [product stringValue];
}
 
NSLog(@"%@",decimalNumberMutiplyWithString([NSString stringWithFormat:@"%f",a], [NSString stringWithFormat:@"%d",b])); //输出结果 999999.99

通过计算每一位的数字,再进行string展示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- (NSString *)convertStringFromFloatNum:(NSNumber *)floatNum
{
    NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
    [numberFormatter setPositiveFormat:@"0.00"];
    NSString *tempFloatStr = [numberFormatter stringFromNumber:[NSNumber numberWithDouble:([floatNum floatValue] * 100)]];  // yuan to fen
 
    NSInteger tempInt = [tempFloatStr integerValue];
 
    NSInteger result = tempInt % 100;
    if (0 == result) {
        NSString *str = [NSString stringWithFormat:@"%zd", tempInt/100];
 
        return str;
    }
 
    result = tempInt % 10;
    if (0 == result) {
        NSString *str = [NSString stringWithFormat:@"%zd.%zd", tempInt/100, (tempInt % 100)/10];
 
        return str;
    }
 
    NSString *str = [NSString stringWithFormat:@"%zd.%zd%zd", tempInt/100, (tempInt % 100)/10, (tempInt % 100)];
 
    return str;
}

30.个推iOS10改动

iOS 10 中 “loc-key”和“body”(我们官网就是“message”)这二个字段的优先级发生了变化,在iOS 10中“body”的优先级大于“loc-key”,在iOS 10以下“loc-key”大于“body”,不推荐使用“body”传递数据

将Message(对应body)中的数据放到payload中,将loc-key的数据放到message(对应body)中,在iOS 10中就不会出现显示代码了

31.iOS10 默认的frame

32.腾讯手机管家 骚扰拦截 数据库更新失败

骚扰拦截功能,进行数据库更新时,如果是英文环境,一直会出现数据库更新失败,切换到中文环境,一次性就成功了。