iOS DevelopmentiOS Developer恩美第二个APP项目

iOS开发小技巧

2016-08-23  本文已影响1311人  s_在路上

AFNetworking网络请求返回3840错误解决方案

场景:

在日常开发的时候,跟PHP对接接口的时候,可能会有这样的约定,接口正常返回的数据信息或者一些用于提示用户和开发者的错误信息,使用AFNetworking解析成功的时候会以code、mag、data这种返回:

{
  code = 0;
  data = <__NSArrayI 0x600000646270>(
        10号线,
        天通苑,
        回龙观,
        青年路
  )
  mag = @""; 
}   

针对这种情况,只需要判断code码即可,根据不同的code码显示不同的信息。
但是,有可能跟PHP对接接口的时候,遇到这总情况,接口正常返回的数据信息如下:

image.png

一些用于提示用户和开发者的错误信息会已,都会在error里面显示,比如:

image.png

针对这总情况的时候,怎么去解析error里面的信息,下面是解决方案:

image.png image.png

只需要在failure里面添加下面的代码。

NSData *data = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey];  
  if (data != nil) {  
      NSString *error = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];  
      NSLog(@"error--%@", error); // 就可以获取到错误时返回的body信息。  
}   

从AFNetworking源码中可以看出,AFNetworkingOperationFailingURLResponseDataErrorKey这个key对应着error里面的useInfo的data。

image.png

修改Xcode自身生成的文件注释

image.png

首先右键:
Xcode -->选项-->在Finder中打开-->右键-->显示包内容-->Contents-->Developer-->Platforms-->iPhoneOS.platform-->Developer-->Library-->Xcode-->Templates-->File Templates-->Source-->Cocoa Touch Class.xctemplate

image.png image.png

注释就是我们要修改的,注意格式,跟我们创建文件的头部注释是一样的。

这里用到了几个系统的预处理宏定义,包括__FILENAME____PROJECTNAME____FULLUSERNAME____DATE____COPYRIGHT__,分别表示的是文件名、项目名称、系统用户全称、当前日期和版权声明,这些宏定义可以用在我们修改之后的注释中,然后,自定义注释的格式,退出Xcode重新运行,然后创建新类,我们就会发现新的类文件格式:

image.png

忽略不必要的警告⚠️

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        return [target performSelector:action withObject:params];
#pragma clang diagnostic pop

iterm2 安装 powerline

image.png

解决方案

pip install powerline-status --user

获取float的前两位小数

当我们直接把 float 转为 NSString 会发现小数点后有很多小数,可以按照需求截取几位小数:

NSString *strDistance = [NSString stringWithFormat:@"%.xf", kilometers]; // x表示具体显示多少位

pop 到指定 ViewController

UINavigationController 有个 Property,是一个存储所有 pushnavigationcontroller 的视图的集合,是一个栈结构,当我们要 pop 到某个 ViewController 的时候,直接用 for in 去遍历 viewControllers 即可:

for (UIViewController viewController in self.navigationController.viewControllers) {
    if ([viewController isKindOfClass:[AccountManageViewController class]]) {
        [self.navigationController popToViewController:viewController animated:YES];
    }
}

通过 View 获取 ViewController

为了做到数据与视图的分离,我们一般会将一个页面的局部视图以自定义 UIView 的方式独立出来,如果在该视图中有触发事件(事件处理不需要父视图的上下文),就会遇到在 UIView 中获取 UIViewController 的情况,可以写一个 UIView 的范畴 UIView(UIViewController)

#pragma mark - 获取当前view的viewcontroller
+ (UIViewController *)getCurrentViewController:(UIView *) currentView {
       for (UIView* next = [currentView superview]; next; next = next.superview) {
             UIResponder *nextResponder = [next nextResponder];
             if ([nextResponder isKindOfClass:[UIViewController class]]) {
                  return (UIViewController *)nextResponder;
             }
      }
     return nil;
}

为文本加上下划线

基本就是用 NSMutableAttributedString 代替原来的 NSString,然后为文本长度的 range 内添加一个下划线的属性。

NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:button.titleLabel.text];
NSRange strRange = {0,[string length]};
[string addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:strRange];
[button setAttributedTitle:string forState:UIControlStateNormal];

二级页面隐藏 tabbar

一般会在 TabBarController 中设置多个 NavigationController 作为各个 tabViewController。我们只要写一个 BaseViewController,在其中重写 pushViewController:animated 方法,在其中判断是否需要隐藏就行。设置 hidesBottomBarWhenPushed 属性来控制在跳转的时候隐藏。

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    if (self.viewControllers.count) {
        viewController.hidesBottomBarWhenPushed = YES;
    }
    [super pushViewController:viewController animated:animated];
}

设置Xcode在release下执行静态分析

Build Settings选项中的搜索栏中搜索关键字analyze during ‘Build’,将Release下面设置为Yes即可。

iOS cocoapods一些用法备忘

一般我们在Podfile文件中指定在某个特定的scheme下引用某个框架,写法如下:

pod 'PgyUpdate', :configurations => ['Adhoc','AdhocDebug']
pod 'Reveal-iOS-SDK', '1.5.1', :configurations => ['Debug']

可以指定某个自定义框架的地址:

pod 'zucheLib_Category', :git => 'http://10.3.4.127:8888/ios_team/zuchelib_category.git', :tag => ‘0.1.2’

如果在自定义的框架下,我们使用#if DEBUG这种定义模式来区分,那么在默认Pods中是无效的。需要使用以下方法打开Debug的编译配置:

post_install do |installer_representation|
    installer_representation.pods_project.targets.each do |target|
        if target.name == 'zucheLib_Networking'
            target.build_configurations.each do |config|
                if config.name != 'Release'
                    config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'DEBUG=1']
                end
            end
        end
    end
end

如果多个target都需要引用某些公共的Pods类库框架可以使用如下写法:

def shared_pods
   platform :ios, '7.0'
   inhibit_all_warnings!  # 关闭所有警告
   #network
   pod 'AFNetworking', '~> 3.0'
end
target "XXXXXXX" do
   shared_pods
end

UILabel设置行间距并且计算文本高度所占内容

有时候我们在有些文本设计中需要对行间距有一些特殊的要求,那么uilabel是不能直接设置行间距的,那么我们应该如何来设置行间距呢?

设置行间距

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:self.stringData];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineSpacing:10]; // 调整行间距
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [self.stringData length])];
contentLabel.attributedText = attributedString;

计算带有行间距的文本的高度

- (CGSize)getSizeWithLabelString:(NSString *)text
                            font:(UIFont *)font
                            width:(NSInteger)width
                            lineSpace:(NSInteger)lineSpace {
   NSMutableAttributedString *attributedString =
   [[NSMutableAttributedString alloc] initWithString:text];
   NSMutableParagraphStyle *paragraphStyle =
   [[NSMutableParagraphStyle alloc] init];
   
   [paragraphStyle setLineSpacing:lineSpace];
   [attributedString addAttribute:NSParagraphStyleAttributeName
                            value:paragraphStyle
                            range:NSMakeRange(0, text.length)];
   
   CGSize stringSize =
   [text boundingRectWithSize:CGSizeMake(width, MAXFLOAT)
                      options:NSStringDrawingUsesLineFragmentOrigin |
    NSStringDrawingUsesFontLeading |
    NSStringDrawingTruncatesLastVisibleLine
                   attributes:@{
                                NSFontAttributeName : font,
                                NSParagraphStyleAttributeName : paragraphStyle
                                } context:nil].size;
   
   return stringSize;
}

iOS动态获取UILabel的高度和宽度

在使用UILabel存放字符串时,经常需要获取label的长宽数据,本文列出了部分常用的计算方法。

1.获取宽度,获取字符串不折行单行显示时所需要的长度:

CGSize titleSize = [aString sizeWithFont:font constrainedToSize:CGSizeMake(MAXFLOAT, 30)];

注:如果想得到宽度的话,size的width应该设为MAXFLOAT。

2.获取高度,获取字符串在指定的size内(宽度超过label的宽度则换行)所需的实际高度:

CGSize titleSize = [aString sizeWithFont:font constrainedToSize:CGSizeMake(label.frame.size.width, MAXFLOAT) lineBreakMode:UILineBreakModeWordWrap];

注:如果想得到高度的话,size的height应该设为MAXFLOAT。

3.实际编程时,有时需要计算一段文字最后一个字符的位置,并在其后添加图片或其他控件(如info图标),下面代码为计算label中最后一个字符后面一位的位置的方法。

CGSize sz = [label.text sizeWithFont:label.font constrainedToSize:CGSizeMake(MAXFLOAT, 40)];
CGSize linesSz = [label.text sizeWithFont:label.font constrainedToSize:CGSizeMake(label.frame.size.width, MAXFLOAT) lineBreakMode:UILineBreakModeWordWrap];
if (sz.width <= linesSz.width) { //判断是否折行
    lastPoint = CGPointMake(label.frame.origin.x + sz.width, label.frame.origin.y);  
} else {  
    lastPoint = CGPointMake(label.frame.origin.x + (int)sz.width % (int)linesSz.width,linesSz.height - sz.height);  
}

ios7以后废弃了以上方法,转而采用下面这种方式来计算:

NSMutableParagraphStyle *pstyle = [[NSMutableParagraphStyle alloc] init];
pstyle.lineBreakMode = NSLineBreakByWordWrapping;
CGSize titleSize = [titleString sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:self.data.titleFontSize],NSParagraphStyleAttributeName:pstyle}];
CGRect titleRect = [titleString boundingRectWithSize:titleSize
                                                options:NSStringDrawingUsesLineFragmentOrigin
                                             attributes:@{NSParagraphStyleAttributeName: pstyle} context:nil];

执行brew install node

Paste_Image.png
Error:Cannot write to /usr/local/Cellar

解决方法:
Check the permissions:

ls -ld /usr/local/Cellar

Open them up for writing:

sudo chmod a+w /usr/local/Cellar

Xcode插件管理器Alcatraz的安装和使用

一、简单说明
Alcatraz 是一款 Xcode 的插件管理工具,可以用来管理 XCode 的插件、模版以及颜色配置的工具。
二、如何安装
1、github地址:https://github.com/alcatraz/Alcatraz
2、安装方法
方法一:在命令行中输入如下指令:

curl -fsSL https://raw.github.com/alcatraz/Alcatraz/master/Scripts/install.sh | sh

图示:


Paste_Image.png

注意:
在安装的过程中需要先把 XCode 退出,等安装完成之后重新打开 XCode。等 Alcatraz successfully installed,表示已经安装成功了。打开之后,会弹窗如下图所示,选择 load bunble

方法二:通过上面的 github 地址下载 Alcatrazcommand +r 运行,完成后 command+q 退出 XCode 重启。

此时打开 XCode 可以检查是否安装成功。

屏幕快照 2016-07-18 下午10.39.51.png

三、如何使用
1、如何使用 Alcatraz 来安装插件
Alcatraz 安装成功后,选择Window->package Manager,会打开 Alcatraz 的工作窗口。假设我们需要安装的VVDocumenter-Xcode插件,那么在搜索框中直接搜索VVDocumenter-Xcode即可。搜索完成之后界面显示如下。

Paste_Image.png
点击 INSTALL 即可安装该插件,插件安装完成之后。显示如下,INSTALL 按钮变成 REMOVE 按钮。 Paste_Image.png

command+qXCode 退出,重新打开,选择下图中的 load bundle 按钮,到此 VVDocumenter-Xcode 就已经安装好了,可以直接使用。

450136-20151114165155087-84937224.png

2、如何使用 Alcatraz 来卸载插件
我们可以通过 Alcatraz 来查看当前 XCode 中集成了哪些插件。如果要卸载相关插件非常简单,点击插件左边的 Remove 按钮即可。

Paste_Image.png

四、如何卸载
命令行输入:

rm -rf ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins/Alcatraz.xcplugin

神器iTools的巧妙使用

这几天,公司项目不怎么忙,然后利用些业余的时间,想仿一个app。下面介绍一下如果获取其他app的图片资源:
步骤
1、在MacX下载iTools软件,并安装,直接在百度上搜也能找到。

Paste_Image.png

2、双击安装iTools,安装陈宫之后,在iTools中点击资源库,如果你连接上你的iPhone,这个按钮就在右上角,若没有连接iPhone,该按钮就在坐下角。

Paste_Image.png Paste_Image.png

3、左边有网络资源和手机资源,点击网络资源下的苹果应用,在右上角搜索你要仿写的app,点击下载,此时如果你连着iPhone显示的就不是下载而是安装,此时会提示你输入apple id。这里以闲鱼为例:

Paste_Image.png Paste_Image.png

4、选中下载的软件,然后点击上面的那一排按钮中的导出,保存到桌面上。


Paste_Image.png

在桌面上找到下载好的ipa文件,右键该文件,选择一个解压软件打开该文件,切记不要使用iTunes打开,此时该路径下便会有个文件夹名为项目名称的文件夹。可以导出到桌面然后结归档就好了。


Paste_Image.png
5、把解归档的文件夹进行打开就好了,资源都在里面,随便拿,有时候是乱的需要自己整理。
Paste_Image.png

以上就是总结好的,神器iTools的巧妙使用。

dSYM 文件分析工具

如果项目中使用了友盟统计,对于友盟给出的错误信息统计,比如数组越界却只给出了 -[__NSArrayM objectAtIndex:]: index 50 beyond bounds [0 .. 39] 这类错误信息,如下图所示:

友盟统计

遇到这种问题一般会非常苦恼,也不知道项目中哪一个地方数组越界了。

1、什么是 dSYM 文件
Xcode 编译项目后,我们会看到一个同名的 dSYM 文件,dSYM 是保存 16 进制函数地址映射信息的中转文件,我们调试的 symbols 都会包含在这个文件中,并且每次编译项目的时候都会生成一个新的 dSYM 文件,位于 /Users/<用户名>/Library/Developer/Xcode/Archives 目录下,对于每一个发布版本我们都很有必要保存对应的 Archives 文件。

Paste_Image.png

2、dSYM 文件有什么作用
当我们软件 release 模式打包或上线后,不会像我们在 Xcode 中那样直观的看到用崩溃的错误,这个时候我们就需要分析 crash report 文件了,iOS 设备中会有日志文件保存我们每个应用出错的函数内存地址,通过 XcodeOrganizer 可以将 iOS 设备中的 DeviceLog 导出成 crash 文件,这个时候我们就可以通过出错的函数地址去查询 dSYM 文件中程序对应的函数名和文件名。大前提是我们需要有软件版本对应的 dSYM 文件,这也是为什么我们很有必要保存每个发布版本的 Archives 文件了。

3、dSYM工具

下载 dSYM工具

Paste_Image.png

注意:


Paste_Image.png

1、就是每次 upload 发布版本所对应的 Archives 文件,直接拖到 dSYM 分析工具里面。
2、在 dSYM 分析工具里面点击 Archives 文件,UUID 自动填充。

Paste_Image.png

3、打开统计(我们用的友盟统计),输入 Slide Address

Paste_Image.png

4、分析,针对项目中的 Base Address,逐个分析。

Paste_Image.png

5、看到有可能出错的地方,逐个排查。

Charles之http、https配置

Paste_Image.png

一. Charles安装
官网下载安装Charles:https://www.charlesproxy.com/download/
二、http配置
1、查看电脑IP地址
在终端上

   ifconfig en4
Paste_Image.png

或者

Paste_Image.png

2、手机http代理配置
手机必须和电脑连接同一个局域网,点击“设置->无线局域网->选择连接的WiFi”,设置http代理:


Paste_Image.png

端口号:8888
注意:端口号随便写。
3、Charles进行http配置

Paste_Image.png Paste_Image.png

以美团返回的数据为例:


Paste_Image.png

三、https代理配置
https代理配置必须要安装SSL证书
1、在手机上安装SSL证书
点击 Help -> SSL Proxying -> Install Charles Root Certificate on a Mobile Device


Paste_Image.png

点击安装,得到SSL证书安装的地址


Paste_Image.png

在手机Safari浏览器输入地址 chls.pro/ssl,出现证书安装页面,点击安装

Paste_Image.png Paste_Image.png

2、Charles进行https配置
点击 Proxy -> SSL Proxying Settings...

Paste_Image.png
勾选Enable SSL Proxying,点击Add。以https://api.weibo.cn为例,端口号填写443
Paste_Image.png Paste_Image.png
上一篇 下一篇

猜你喜欢

热点阅读