iOS开发经验总结

本文分享了iOS开发中遇到的问题及解决方法,包括TapGesture使用注意事项、block声明方式、TTTAttributedLabel设置文本最佳实践、MagicalRecord数据库操作、UILabel文字偏移处理等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文根据开发中遇到的问题以及总结的经验,会不断的更新

 

1. TapGesture使用要注意,当对某一个view使用tapGesture之后,发到这个view上的touchBegin等方法不正常,具体表现为touchBegin发出之后,接着发出touchCancel,很少的情况下在gesture失效的时候才会有touchEnd,具体过程是我在使用TTTAttributedLabel的时候把TTTAttributedLabel放在了一个view上,又为该view添加了一个tapGesture,于是TTTAttributedLabel中定义的link操作没有收到,请看相关链接https://github.com/TTTAttributedLabel/TTTAttributedLabel/issues/266, 注意里面getaaron这个人的回答

 

2.对于block,都应该使用copy来声明,原因是block来捕获上下文的信息。【官方文档】Objects Use Properties to Keep Track of Blocks

 

3.创建容器对象,比如NSArray和NSDictionary的时候必须严格的check放入的object是否是nil。

 

4.TTTAttributedLabel的text应该在最后才设置,否则frame和换行等会出现问题。

 

5.使用MagicalRecord操作数据库的时候,会用到contextForCurrentThread方法从当前线程获取context,但是在串行队列里面并不能保证每次拿到的context都是一样的,具体情况见Why contextForCurrentThread Doesn't Work in MagicalRecord,目前好像有些打不开,可以看其他的引用文章Why contextForCurrentThread Doesn't Work in MagicalRecord

 

6. 应用在后台运行的代码:

 

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    __block UIBackgroundTaskIdentifier bgTask = UIBackgroundTaskInvalid;
    bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (bgTask != UIBackgroundTaskInvalid) {
                bgTask = UIBackgroundTaskInvalid;
            }
        });
    }];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (bgTask != UIBackgroundTaskInvalid) {
                bgTask = UIBackgroundTaskInvalid;
            }
        });
    });
}

 

但其实不是应用一直在运行。

 

 

7. 计算一段NSString在视图中渲染出来的尺寸

 

+ (CGSize)sizeOfString:(NSString *)textString font:(UIFont *)font bound:(CGSize)bound {
    NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
    paragraphStyle.alignment = NSTextAlignmentLeft;
    if (font == nil) {
        font = [UIFont systemFontOfSize:[UIFont systemFontSize]];
    }
    NSDictionary * attributes = @{NSFontAttributeName : font,
                                  NSParagraphStyleAttributeName : paragraphStyle};
    
    NSAttributedString* attributedString = [[NSAttributedString alloc] initWithString:textString attributes:attributes];
    return [TTTAttributedLabel sizeThatFitsAttributedString:attributedString
                                            withConstraints:CGSizeMake(bound.width, 999)
                                     limitedToNumberOfLines:0];
}


不能使用NSString的[NSString boundingRectWithSize: options: attributes: context:]方法获取到的尺寸偶尔会不准,故不推荐使用。TTTAttributedLabel在这里是使用的CoreText框架进行渲染,更准确一些。

可以参考http://stackoverflow.com/a/37773093/1115791 上我的回答,以及其他人对该问题的回答

 

8. 获取facebook数据,需要在login的时候设置权限,然后通过graph request请求数据,也要配置相应的参数,详情见https://developers.facebook.com/docs/facebook-login/permissions/#reference-user_work_history

 

9. TTTAttributedLabel使用addLinkToURL:withRange:方法添加链接,传入的URL不能是带空格的,否则点击传回的参数是nil。想一想也很简单,URL怎么可能有空格。

 

10. 自己添加字体文件之后在使用的时候设置fontName可能不知道用什么名字,特别当你加入到工程中的文件名是修改过的情况下,使用如下代码可以获取对应的font name:

 

for(NSString *fontfamilyname in [UIFont familyNames])
{
    NSLog(@"Family:'%@'",fontfamilyname);
    for(NSString *fontName in [UIFont fontNamesForFamilyName:fontfamilyname])
    {
        NSLog(@"\tfont:'%@'",fontName);
    }
    NSLog(@"~~~~~~~~");
}

 

 

11. NSUserDefault不能存放可变数据,比如NSMutableArray不能直接存放到NSUserDefault中。经过测试,直接将NSMutableArray存放到NSUserDefault中是可以成功的,但是取出来的时候就不再是NSMutableArray了,而是NSArray,这样修改的时候要转换成NSMutabelArray才能修改。这也是合理的,NSUserDefault其实是存在一个文件里的,怎么可能是可变数据。

 

 

 

12. 有时候需要将UILabel上的文字进行一下偏移处理,由于UILabel没有xxxinset这样的属性,所以要实现这个只有使用其他办法,以下是我的实现方式,将UILabel里的文字向Y方向偏移了2个点:

 

signupLabel.layer.transform = CATransform3DMakeTranslation(0, 2, 0);//由于字体的原因,做偏移

 

13. 同12类似,由于自定义字体的原因,在button上显示的字符串向上偏移了一些,需要将这个往下偏移才行:

 

 

button.titleEdgeInsets = UIEdgeInsetsMake(3, 0, 0, 0);//由于字体的原因,做偏移

 

14. 使用Masonry约束TTTAttributedLabel的时候,初始化TTTAttributedLabel需要设置frame为CGRectZero,否则约束会不生效。

 

15. SVProgressHUD如果要自定义一些属性,比如loading状态转圈的颜色,必须先设置style为SVProgressHUDStyleCustom,这样自定义的状态才会生效。

 

16. github下载的代码有submodule目录的时候,依次执行以下步骤:
git submodule init
git submodule update

如果不生效,先clone,再执行以上命令

 

17. 更新UITableView的datasource的操作最好和刷新UITableView的操作一起都放在主线程里面。

之前遇到一个问题是从服务器拉取数据下来之后在后台线程处理,然后更新datasource,接着dispatch到main线程对UITableView进行reloadData操作。调试过程中发现当我修改datasource之后,cellForRow方法被调用了,并且是越界的index,造成了crash,这过程中很奇怪的是没有调用numberOfRows,而是回调了cellForRow,最后把修改数据的刷新UI操作都放到main线程之后就搞定了。

 

18.有时候在一个循环里面需要根据条件打印一些log,又不想加代码进去,这样就可以用到条件断点

这里的重点是把要打印的内容用两个@符号括起来。如果不想断点处停下来,可以勾中下面的Automatically continue after evaluating actions,这样log会正常打印,但是不会在这里断下来

 

19. 同时向UITableView中批量添加删除数据的时候偶尔会crash,可以将insert, delete, update操作放在一个beginUpdates和endUpdates代码中间。

具体处理方案可以参考:Batch updates for UITableView and UICollectionView

 

20. NSString的stringByAppendingString这类方法很容易因为参数为nil造成crash,一定要在使用的时候进行参数合法性检测。

 

21. 在处理将时间字符串转为NSDate的时候偶尔会遇到夏时令的问题导致转不出NSDate,为了处理这个问题,我之前都是对实行过夏时令的时间进行加1处理,后来发现这个时间会比较多,而且我实际上只处理了中国的情况,为了处理所有情况,还需要有其他的方式。对于夏令时的信息,可以参考Time Zone in Shanghai, Shanghai Municipality, China, 解决方案参考iOS开发之夏令时,NSDateFormatter格式化失败

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值