每周 Swift 社区问答 2016-01-06
作者:shanks & pmst 本周整理问题如下:
对应的代码都放到了 github 上,有兴趣的同学可以下载下来研究:点击下载 Question1: Question on extracting a substring from a urlQ1链接地址 问题描述这个问题在实战中经常被提及,譬如现在有一个字符串URL:https://api.github.com/gists/public?page=2 ,我需要从中提取出“?page=2”以及“https://api.github.com/gists/public”,将这两个部分存储到两个变量中,如下: var strBase = "https://api.github.com/gists/public" var strPage = "?page=2" 问题解答前了解下小知识:
问题解答思路:显而易见,关注点应该放在?上,解决方式也五花八门,现提供以下几种方式:
这里的 对于
这里是使用了 let parts = urlStr.componentsSeparatedByString("?") // 1 strBase = parts[0] // 2 strPage = parts.count >= 2 ? "?" + parts[1] : ""
if let urlCompo = NSURLComponents(string: urlStr) { strPage = urlCompo.query != nil ? "?" + urlCompo.query! : "" urlCompo.query = nil strBase = urlCompo.string! } else { fatalError("invalid URL") } 举一反三,如果我还想获得请求参数中的各个参数,那应该怎么做呢?我先抛砖引玉下: var urlStr1 = "https://api.github.com/gists/public?page=2&name=machao&pwd=222" let parts1 = urlStr1.componentsSeparatedByString("?") strBase = parts1[0] var strPara = parts1.count >= 2 ? "?" + parts[1] : "" strPara.removeAtIndex(strPara.startIndex) let Paras1 = strPara.componentsSeparatedByString("&")//就是这个! Question2: All func pointers need a protocol now?Q2链接地址 问题描述Gargoyle 想实现一个对象之间的回调,但是却未使用 protocol + delegate 的设计模式,而是使用了如下方法: final class MyView: UIView { var onSomeAction: ((String) -> Void)! } final class MyViewController: UIViewController { let myView = MyView(frame: CGRectZero) override func viewDidLoad() { super.viewDidLoad() myView.onSomeAction = someFunc } private func someFunc(str: String) { } } 注意到 问题解答Jessy 提供了一种解决方案: var onSomeAction_get: () -> (String -> Void)! = {nil} myView.onSomeAction_get = {[unowned self] in self.someFunc} 首先对闭包类型进行了修改,从 Question3: Property for Double and CGFloatQ3链接地址 问题描述Albinus 希望判断是一个随意给定的 number 是否是整型,譬如给定一个 number 是 Double 类型,他现在是通过extension 来实现的,代码如下: extension Double { var isInteger: Bool { return Double(self) == Double(Int(self)) } } 注意到通过 extension 扩展了一个computed property 再来说说其他数字类型,譬如 CGFloat 、 Float 等等,我们都可以通过 extension 依葫芦画瓢来实现,不过有木有更简单,直观的方式呢? 问题解答OOPer 给出了自己解答: protocol IntegerCheckableFloatType: FloatLiteralConvertible,Equatable { func % (lhs: Self,rhs: Self) -> Self // % 可是取余运算符哦 var isInteger: Bool {get} } extension IntegerCheckableFloatType { var isInteger: Bool { return self % 1.0 == 0.0 as Self } } extension Double: IntegerCheckableFloatType {} extension CGFloat: IntegerCheckableFloatType {} extension Float: IntegerCheckableFloatType {} (123.4).isInteger //->false (123.0).isInteger //->true 首先定义 对于 typealias FloatLiteralType /// Create an instance initialized to `value`. public init(floatLiteral value: Self.FloatLiteralType)
public func ==(lhs: Self,rhs: Self) -> Bool 从名称就知道这个协议用于 现在巧妙的是我们使用了 Protocol 中的 extension 特性,为协议增加了默认行为,如下: extension IntegerCheckableFloatType { var isInteger: Bool { return self % 1.0 == 0.0 as Self } } 根据协议的知识,一个类型遵循了某个协议,那么必须实现该协议中的所有“要求”。但是!倘若你使用了 extension 特性为协议增加了一个默认行为,那么类型遵循了该协议,本身却不实现,则会调用默认行为。就拿上文例子说吧,如果类型遵循了 再来看看后面部分: extension Double: IntegerCheckableFloatType {} extension CGFloat: IntegerCheckableFloatType {} extension Float: IntegerCheckableFloatType {} 我们令 Question4: Question on dismissing model ViewController问题链接Q4链接地址 问题描述VolmDev 问了一个自己在实际开发中遇到的问题:应用需要登录操作,为此当主界面出现之后,跳转到登陆界面,输入账号密码,点击 Login 按钮,关闭登陆界面,回到主界面,一切就应该结束,不是吗? 可问题偏偏出现了!当关闭登陆界面后居然又跳出了登陆界面!再关闭又打开? VolmDev 抓狂了,这尼玛什么情况!他附上了完整的代码,如下: 这是ViewController.swift 文件源代码: // ViewController.swift import UIKit import SafariServices class ViewController: UIViewController,LoginViewDelegate { var safariViewController: SFSafariViewController? override func viewDidLoad() { super.viewDidLoad() } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) showPopUp() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } func showPopUp() { let storyboard = UIStoryboard(name: "Main",bundle: NSBundle.mainBundle()) if let loginVC = storyboard.instantiateViewControllerWithIdentifier( "LoginViewController") as? LoginViewController { loginVC.delegate = self self.presentViewController(loginVC,animated: true,completion: nil) } } // delegate function. func didTapLoginButton() { self.dismissViewControllerAnimated(false,completion: nil) // if let authURL = GitHubAPIManager.sharedInstance.URLToStartOAuth2Login() { // safariViewController = SFSafariViewController(URL: authURL) // safariViewController?.delegate = self // if let webViewController = safariViewController { // self.presentViewController(webViewController,completion: nil) // } // } } } 这是 LoginViewController.swift 文件源代码: // LoginViewController.swift // TestingPopUps import UIKit // this is a delegate function that can be used // to call a funct+-*`*ion outside this class to do // something on behafe of this class. protocol LoginViewDelegate: class { func didTapLoginButton() } class LoginViewController: UIViewController { weak var delegate: LoginViewDelegate? @IBAction func btnDismiss(sender: AnyObject) { // Note: I tried dismissing here too with failure //self.dismissViewControllerAnimated(false,completion: nil) if let delegate = self.delegate { delegate.didTapLoginButton() } } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } 当然,storyboard 还有些不关紧要的东西,倘若有兴趣,你可以自己来补充。 倘若不想看源代码思考下,请直接跳转到问题解答。 问题解答该例出现的问题其实很简单,但也是新手经常犯的错误。贴出逻辑错误的部分: override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) showPopUp() } 当 viewController 的主视图出现之后,调用showPopUp方法弹出登陆界面,貌似没什么错误。此时登陆界面位于主视图之上,输入账号密码之后点击按钮,通过 protocol+delegate 方法告知 viewController 视图控制器用户点击了登陆按钮,此时事件处理只是简单的关闭登陆视图: func didTapLoginButton() { self.dismissViewControllerAnimated(false,completion: nil) } 关闭视图之后,意味着 viewController 的视图又出现了!那么就会调用 思考今天的问题很基础,但是同样有我们值得学习的地方,我简单归纳下:
Question5: count numbers in array and order them by count in swift问题链接Q5链接地址 问题描述楼主提了一个算法问题: 例如: [1,2,3,5,5] 经过计算得到的结果是: [5,1] 问题解答问题解答思路也比较简单,首先是要计算每个元素在数组中出现的次数,然后再做排序。 解法1: extension SequenceType where Generator.Element : Hashable { func frequencies() -> [Generator.Element:Int] { var results : [Generator.Element:Int] = [:] for element in self { results[element] = (results[element] ?? 0) + 1 } return results } } let alpha = [2,8,6,1,6] let beta = [6,1] let sorted = alpha.frequencies().sort { if $0.1 > $1.1 { // if the frequency is higher,return true return true } else if $0.1 == $1.1 { // if the frequency is equal return $0.0 > $1.0 // return value is higher } else { return false // else return false } } 解答2: var arr1 = [2,6] var arr2 = [6,1] var counting = [Int: Int]() // fill counting dictionary for num in arr1 { if counting[num] != nil { counting[num]!++ } else { counting[num] = 1 } } // [6: 3,2: 3,8: 2,1: 1] print(counting) func order(i1: Int,i2: Int) -> Bool { let count1 = counting[i1] let count2 = counting[i2] // if counting is the same: compare which number is greater if count1 == count2 { return i1 > i2 } else { return count1 > count2 } } // [6,1] print(arr1.sort(order)) print(arr2) Question6: Cannot invoke [Method] with argument list of type (,)问题链接Q6链接地址 问题描述楼主的问题是: protocol A { } protocol B: A { } class Utility { func add<T:A>(t:T.Type,param:T){ } } class Test { var util: Utility init() { util = Utility() } func addItem(data:B){ //util.add(B.self,param: data) //这里报错:expected an argument list of type '(T.Type,param: T)' } } 问题解答楼主把 data 的类型定义为协议 B,这不是正确的用法,应该定义一个泛型类型 T,T 遵从 B 协议,见以下代码: class Test1 { var util: Utility init() { util = Utility() } func addItem<T: B>(data: T) { util.add(T.self,param: data) } } Question7: Swift programming style问题链接Q7链接地址 问题描述楼主的问题是:extension 存在的意义是啥,为什么不直接写到一个定义里面,比如: struct xxx { } extension xxx { func yyy() {} } //: 可以合并成以下代码: struct xxx1 { func yyy() {} } 问题解答此问题其实很容易解答,extension 存在的意义,是去扩展已有的类型,而不是新建了类型,而去用 extension 扩展新的逻辑。比如,对 Int,Double 新增功能,就需要用到 extension。跟帖中也建议楼主好好读读官方文档,理解一下extension存在的价值。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |