• 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

    1693553-c69c8c0bb2f028fc.png

    图形搜索法

    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的,右键点击警告

    1693553-0c9c4205967fc123.png

    警告

    2)查看警告的详情

    1693553-5f9a233c1f20cfe3.png

    详情

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

    1693553-587e5e85b775bfaa.png

    搜索

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

    1693553-e349b03e0ed30083.png

    找到Label

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

    1693553-e92f73274859a206.png

    设置

    6)警告解决

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

    11.png

    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文件:

    16.png

    注意:
    当使用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.腾讯手机管家 骚扰拦截 数据库更新失败

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

  • 相关阅读:
    用AjaxMethod 方法实现动态加载地图
    C#中HashTable的使用(转)
    ArcGIS Server 中的动态文字标注
    ArcGIS Server .Net Web ADF之几何类型的相互转换(转)
    ArcGIS Server连接远程地图服务器
    sqlplus环境配置(login.sql)
    Oracle从软件安装到运行的全流程
    【转载】linux中误删除oracle数据文件的恢复操作
    “大淘宝战略”下集市定位,将决定马云和未来淘宝的命运
    男人如何对待抱怨自己的女人
  • 原文地址:https://www.cnblogs.com/GJ-ios/p/6483091.html
Copyright © 2020-2023  润新知