问题

cocoapods 安装Alamofire出现的问题,执行pad install之后没有生成对应的xxx.xcworkspace的文件(Podfile文件格式没有错误)

网上查询可能是ruby版本问题(其实应该是cocoapods自身问题,升级到1.1.1之后),开始升级ruby(用brew安装更加方便)

1.安装rvm

curl -L get.rvm.io | bash -s stable

2.测试是否安装正常

rvm -v

出现版本号代表安装正常

  1. 查看ruby的所有的版本号

  2. rvm list konwn

  3. 选择一个版本安装,我这里是2.4.0

  4. 升级

  5. rvm install 2.4.0

  6. 出现错误如下

  7. Searching for binary rubies, this might take some time. No binary rubies available for: osx/10.12/x86_64/ruby-2.2.4. Continuing with compilation. Please read ‘rvm help mount’ to get more information on binary rubies. Checking requirements for osx. Installing requirements for osx. Updating system – please wait Error running requirements_osx_brew_update_system ruby-2.2.4′, showing last 15 lines of /Users/xielibin/.rvm/log/1487058803_ruby-2.2.4/update_system.log +rvm_error:2> rvm_pretty_print stderr +rvm_pretty_print:2> case auto (0|no) +rvm_pretty_print:2> case auto (1|auto) +rvm_pretty_print:7> case xterm-new (dumb|unknown) +rvm_pretty_print:10> case stderr (stdout) +rvm_pretty_print:10> case stderr (stderr) +rvm_pretty_print:12> [[ -t 2 ]] +rvm_pretty_print:12> return 1 +rvm_error:4> printf %b Failed to update Homebrew, follow instructions here: https://github.com/Homebrew/homebrew/wiki/Common-Issues and make surebrew updateworks before continuing.\n Failed to update Homebrew, follow instructions here: https://github.com/Homebrew/homebrew/wiki/Common-Issues and make surebrew updateworks before continuing. +requirements_osx_brew_update_system:25> return 1 Requirements installation failed with status: 1.

万能的stackoverflow上看了一下,试了如下的命令

Whoops, the Homebrew installer has moved! Please instead run:ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)”

还是出现错误:

Error running ‘requirements_osx_brew_libs_install automake’,

showing last 15 lines of /Users/xielibin/.rvm/log/1487059577_ruby-2.4.0/package_install_automake.log

+rvm_pretty_print:10> case stdout (stdout)

+rvm_pretty_print:11> [[ -t 1 ]]

+rvm_pretty_print:11> return 1

+rvm_warn:4> printf %b ‘There were package installation errors, make sure to read the log.

Try brew tap –repair and make sure brew doctor looks reasonable.

Check Homebrew requirements https://github.com/Homebrew/homebrew/wiki/Installation\n

There were package installation errors, make sure to read the log.

Try brew tap –repair and make sure brew doctor looks reasonable.

Check Homebrew requirements https://github.com/Homebrew/homebrew/wiki/Installation

+requirements_osx_brew_libs_install:8> case 10.12 (10.6)

+requirements_osx_brew_libs_install:15> return 1

Requirements installation failed with status: 1.

brew的配置问题

brew doctor检查

链接

brew link

完成之后

brew install ruby

升级到最新版

备注:完成ruby升级,如果问题还存在(我就存在),那就是cocoapods升级的bug,重新升级安装 sudo gem install cocoapods,重新执行pod install 成功!

解读的一些内容

前言:Alamofire与AFNetWorking是同一个大神写的

0.一些学习的tips

1.将系统的关键字用作变量:`default`, `self`等;

2.一个函数返回结果没有使用系统会有警告,利用@discardableResult可以消除警告;

3.swift2.0的关键字defer(我们用的也比较少):

   语法 defer{ code }

    使用:每一个defer代码块生成之后被放进一个栈中(先进后出),所以这里的代码是自下而上执行的。看一行代码:

func lookforSomething(name:String){
       //这里是作用域1 整个函数作用域
       print(“1-1”)
       if name == “”{
           //这里是作用域2 if的作用域
           print(“2-1”)
           defer{
               print(“2-2”)
           }
           print(“2-3”)
       }
       print(“1-2”)
       defer{
           print(“1-3”)
       }
       print(“1-4”)
       if name == “hello”{
           //作用域3
           print(“3-1”)
           defer{
               print(“3-2”)
           }
           print(“3-3”)
           defer{
               print(“3-4”)
           }
       }
   }

4.避免使用字符串:字符串很容易写错,写错也没有提示,用的地方多了问题就会出现,保不齐什么地方就写错,引起bug,用起来也不爽,看一下Alamofire的使用:

extension Notification.Name {
   // Used as a namespace for all `URLSessionTask` related notifications.
   public struct Task {

   // Posted when a `URLSessionTask` is resumed. The notification `object` contains the resumed `URLSessionTask`.
       public static let DidResume = Notification.Name(rawValue: “org.alamofire.notification.name.task.didResume”)
       //Posted when a `URLSessionTask` is suspended. The notification `object` contains the suspended `URLSessionTask`.

       public static let DidSuspend = Notification.Name(rawValue: “org.alamofire.notification.name.task.didSuspend”)

       //Posted when a `URLSessionTask` is cancelled. The notification `object` contains the cancelled `URLSessionTask`.

       public static let DidCancel = Notification.Name(rawValue: “org.alamofire.notification.name.task.didCancel”)

       // Posted when a `URLSessionTask` is completed. The notification `object` contains the completed `URLSessionTask`.

       public static let DidComplete = Notification.Name(rawValue: “org.alamofire.notification.name.task.didComplete”)
   }
}
extension Notification {
   // Used as a namespace for all `Notification` user info dictionary keys.
   public struct Key {
   // User info dictionary key representing the `URLSessionTask` associated with the notification.
       public static let Task = “org.alamofire.notification.key.task”
   }
}

使用起来就是 Notification.Name.DidResume.rawValue,这样地方多了都不会错。当然定义常量也是可以的,但毕竟swift有这么好的方法,干嘛走老路呢。文件代码很少,用起来却比较的强大。

执行的作用域:defer里面的代码总是在作用域结束之后自下而上调用,可以跑一下自己试试。

场景:可以处理一些错误的逻辑。比如一个函数有1,2,3,4操作,1操作失败需要1.1的处理,2失败需要2.1的处理以此类推,当然defer是自下而上的执行,顺序别弄错(失败的操作依次是4.1-3.1-2.1-1.1),这样写起来相对比自己再去定义方法写一些逻辑要好一点(纯个人理解,我也没用过,理解不是很深)。

1. 整体框架结构

Alamofire.swift: 主要的外部调用的类,发起请求的类,用户可以方便的使用这个类区调用Alamofire的主要功能。

与3.0之前版本的一些区别:3.0的版本一个是转化NSURL(NSURLRequest)为String,即请求的地址的转化。细说就是,  定义URLStringConvertible接口,把系统 String,NSURL,NSURLComponents,NSURLReques转化为String地址,另一个转化NSURLRequest为NSMutableURLRequest;4.0以后的版本是为了swift3做的改变,将地址转化成URL类型,这里增加了错误类型,转化失败会抛出异常,定义URLConvertible接口(与3.0相反),URLRequestConvertible转化成URLRequest,这样做可以做到比较的统一,swift的新思想:面向协议。

SessionManager.swift(3.0版本的Manager.swift): 这是一个单列,主要负责request,封装系统的URLSession等网络请求的类,上述文件中主要调用的就是这个类的方法。

AFError.swift: 封装了各种错误的信息。

Notifications.swift:扩展系统的通知名字,避免使用字符串写错,定义了didResume,didSuspend,didCancel,didComplete等通知名。

ParameterEncoding.swift:定义了参数的编码方式,以ParameterEncoding为接口定义了URLEncoding,JSONEncoding,PropertyListEncoding三种方式,其实就是包装request。

Request.swift: 一共有四个类型:DataRequest, DownloadRequest, UploadRequest, StreamRequest,init会根据不同的类型生成不同的TaskDelegate来处理回调。

Response.swift:对应的也有DefaultDataResponse, DataResponse, DefaultDownloadResponse, DownloadResponse四个类型,四个相互独立没有继承关系,用来解析系统的。

Result.swift:主要就是用于返回接口的解析包装,生成结果对象方便使用(成功及失败的模型)。

SessionDelegate.swift:处理session代理的回调,实际真正处理的是TaskDelegate,封装的较深,可以看做是TaskDelegate的管理者,利用下标去处理request。

TaskDelegate.swift:真正处理session代理的回调。

备注:以上是核心的类

MultipartFormData.swift:用于上传数据(multipart/form-data)的构造类。

NetworkReachabilityManager.swift:用于检测网络的类,封装了SCNetworkReachability。

ResponseSerialization.swift: 用于解析response的工具,可以解析成三种Data ,String,JSON类型;扩展了request,DataRequest,DownloadRequest三个类,基本思想是根据不同的request生成不同的ResponseSerializer(都有遵循的协议),然后按照三种不同的类型去解析。

ServerTrustPolicy.swift:安全策略,使用证书等保证请求的安全。

Timeline.swift:用于开发者调试的类,可以打印一个请求的开始,结束,总时间等。

Validation.swift:请求的验证类,一些错误码 MIMEType错误等的处理。

备注:以上可以看作是工具(辅助)的类

DispatchQueue+Alamofire.swift:简单封装GCD queue的方法。

备注:GCD queue的分类

2.内容解读

   2.1 构造一个框架的一些感想

      首先,划分不同的功能,这个框架需要实现的主要功能和辅助功能的划分;其次,根据不同的功能封装不同的类区处理逻辑,数据,视图;最后,用一个全局的单列或者其他的管理者去方便的使用。宗旨是要用户方便的使用你的框架。

      大致看了Alamofire这个框架,代码不算多,但是分的比较细,功能比较全,使用起来也是很方便。我们之前写的代码时间久了,可能会导致某一个类比较冗陈,可以学习这里的一些封装方法适当的抽代码,给一个类瘦身。

      这个框架用来学习swift的新特性也是不错的,里面的类很多面向协议,这是swift的一大特色。协议比较容易扩展,相对方便维护。泛型和协议,用好这两个特性,可以省去比较多的时间,写出来的代码也比较优雅(还有一个是函数式编程)。

      总的来说,写一个框架需要的全局的概念,确定全局的才能到具体,一步步才能构建一个强大的框架,还有就是任何强大的框架也好,项目也好,都是由简到繁,先写出简易功能,然后一步步扩展(预留好便于扩展的接口)。

  2.2URLComponents

      对于URL这个类使用算是比较的熟悉了,URLComponents相对来说比较陌生。这个其实跟Date与DateComponents相同,可以获取到URL中每一部分的值,大概是这个样子;

 foo://example.com:8042/over/there?name=ferret#nose

  \_/  \______________/ \________/\_________/ \__/

   |      |                  |          |        |

scheme   authority         path       query     fragment

       percent-encoded:加上这个的属性都是经过百分号编码的(针对特殊的字符)。

      Url编码通常也被称为百分号编码(Url Encoding,also known as percent-encoding),是因为它的编码方式非常简单,使用%百分号加上两位的字符——0123456789ABCDEF——代表一个字节的 十六进制形式。Url编码默认使用的字符集是US-ASCII。例如a在US-ASCII码中对应的字节是0x61,那么Url编码之后得到的就 是%61,我们在地址栏上输入http://g.cn/search?q=%61%62%63,实际上就等同于在google上搜索abc了。又如@符号 在ASCII字符集中对应的字节为0x40,经过Url编码之后得到的是%40。

       常见字符的Url编码列表:

!

*

(

)

;

:

@

&

%21

%2A

%22

%27

%28

%29

%3B

%3A

%40

%26

=

+

$

,

/

?

%

#

[

]

%3D

%2B

%24

%2C

%2F

%3F

%25

%23

%5B

%5D

2.3一些封装的思想

      封装要知道哪些是需要开放的,哪些需要封闭的,往往对外封闭的一些内容比较检验一个人的功底。简单的总结几点(欢迎补充):

     a. 有一个总起的类可以调用开放的方法

     b. 独立的东西功能一定要分开写

     c. 代理和闭包同行(很多的框架都会提供两种对外传值)

2.4请求与响应(有些方法写的比较简单)

      Alamofire请求与响应的历程:Alamofire.request()—->   SessionManager.default.request()—–> request.encode()(对请求进行编码,分两种:普通与错误,有三种,参考:1.整体框架结构) —–> SessionDelegate中的回调方法  ———> TaskDelegate中的回调方法   ——-> ResponseSerialization文件中的解析返回数据 ——> 完成。

     大致的一个请求流程就是这样,作者把代理的回调方法都单独到SessionDelegate这个类中,底层是TaskDelegate类处理。这里分闭包调用和代理调用,我们平常的调用,

       let para = [“num”: 20]
       let _ = request(getUrl, method: .get, parameters: para, encoding: URLEncoding.default, headers: httpHeader).responseJSON { (response) in

           switch response.result{
           case .success(let info):
               self.textView.text = “\(info)”
               print(“———post  info: \(info)”)
           case .failure(let error):
               self.textView.text = “\(error)”
               print(“———get  error: \(error)”)
           }
       }

链式的,底层是调用TaskDelegate的代理方法,这里需要说明的一点是:在构造request的时候会持有一个TaskDelegate对象,创建这个对象的时候创建的线程会被直接挂起,

   init(task: URLSessionTask?) {
      self.task = task
       self.queue = {
           let operationQueue = OperationQueue()

           operationQueue.maxConcurrentOperationCount = 1
           operationQueue.isSuspended = true
           operationQueue.qualityOfService = .utility

           return operationQueue
       }()
   }

等到数据返回的时候isSuspended属性会被置为true。这个在哪里用到呢?就是在ResponseSerialization中解析的时候,当解析方法调用的时候会先在task的queue中addOperation,这个闭包中的代码会在任务完成的时候调用,这个时候的数据全部保存在task对象中,然后经过不同的处理(json,string…)返回Response出去,这样:

responseJSON { (response) in
           switch response.result{
           case .success(let info):
               self.textView.text = “\(info)”
               print(“———post  info: \(info)”)
           case .failure(let error):
               self.textView.text = “\(error)”
               print(“———get  error: \(error)”)
           }
       }

这个闭包中就是有返回的数据(都已经封装好的)。当然用闭包那种形式也是可以的,但还是这种链式的用起来比较舒服。

最后:  分享大概就这么多吧,等下次学到更多的tips的时候在接着分享出来。

Post Author: menglingfeng

发表评论

电子邮件地址不会被公开。 必填项已用*标注

You may also like

iOS OC语言copy修饰符实现原理

前言 在经过频繁的业

Label尺寸自适应与AutoLayout问题小结

水平布局与垂直布局L

iOS7之后的导航栏与控制器原点坐标问题

简单记录关于iOS7

%d bloggers like this: