mobile.365-838.com【翻译】 iOS 8 App Extension: Today Widget

By admin in mobile.365-838.com on 2018年10月7日

前言:闲在铺混日子一段时间,就学习Swift,学学iOS8,碰巧遇上这篇稿子,一个下午开下发现死爱掌握,就试试翻译并分享出去。顺便求推荐广州之iOS工作~~~~

如何寻找到温馨“一英尺栏杆”

接触这里看原稿
点这里关押 onevcat
大神的科目

巴菲特有一样句名言:“在投资方面我们因此开得甚成功,是为咱们全神贯注于找我们得轻松过的1英尺栏杆,而逃那些我们没有能力超过的7英尺栏杆。”

以下正文,说明一下,并无是逐字翻译,同时流程以及情发生修改。

咱来有限种植选择:一凡是找到那些“一英尺的槛”,首先难度小多,然后找到过他们可以更的简便动作。虽然从外表看貌似有些避轻就再度,但是:找到,简单动作,重复,这样连循环中贯彻自己价值,就能够得到超过想象的报恩,也非是善事。

  • 假使看官太疲惫了第一手看就结果,可以触这里下载就后底工程,存放于dropbox,记得自备VPN。
  • 再者立即首教程是swift
    1.0底时段写的,打开项目后会见报语法错误,按提示修改就足以。

还有一样种是所谓选择超7英尺的栏杆,先任收益如何,必须明白了之是,凡事找最难以的夺做,这无非称那些极端有天然的人数。对于绝对多数人来讲,绝对免是最好优异选择,当然,世上无难事只怕有心人,也许对于那些特殊之在的话,无难度反而不过瘾呢!


自打投资之角度来拘禁财富累积,从而又快实现财富自由之路来说,最着重之是实现和谐目标。而不刻意不要挑个极端艰难的,来挑战自己,证明下团结。

Step 0:

在iOS
8饱受,苹果店出产的应用程序扩展Extension技术,可以让您的APP扩展原有功能到外界面(通知栏,分享拦),或为不同APP间能够进行数据交互,同时不见面距离时页面。
iOS 8系统有6个支持扩大的系统区域,分别是Today、Share、Action、Photo
Editing、Storage Provider、Custom
keyboard。支持扩大的体系区域为叫称为扩展点。
脚是在IOS的延伸点的列表:

  • Today –
    对于赛事比分,股票、天气、快递这类需要实时落同时以简约的音讯,可以当通报中心的Today视图中创造一个Today扩展实现。Today扩展又曰Widget。

  • Share –
    在系统的享受拦中创建于定义分享,可以享用内容,分享网站要发表消息。

  • Action –
    action在装有支持之壮大点吃扩展性最强的一个。它好兑现转移另一个app上下文中的情。苹果在WWDC大会上演示了一个Bing翻译动作扩展,它好以在Safari中选中的文书翻译成不同的语言。

  • Photo Editing – 在iOS
    8之前,如果你想也卿的像添加一个非正规之滤镜,你要进入第三方app中,这个过程是一定繁琐的。在iOS
    8面临,你可直接以Photos中采取第三方app,如Instagram,VSCO
    cam、Aviary提供的Photo
    Editing扩展完成对图纸的修,而不论是需去时的app。

  • Document Provider – 也为Storage
    Provider,可以为超过多独文本存储服务中间的田间管理变得重新简单。类似Dropbox、Google
    Drive等储存提供商经以iOS 8中提供一个Storage
    Provider扩展,app直接可以采用这些扩展检索和贮文件要不再要创造不必要的正片。

  • Custom Keyboard – 自定义键盘输入法可以吃用户以总体体系范围外采用。

倘若立篇稿子,将聚齐授课 Today Extention 部分。

mobile.365-838.com 1

得的凡找到更契合自己之跑道,以重精的状态去走在重多人口前,以更快的频率来上目的,对于再次多数总人口来讲这才是确实最要害的。

Extention是怎么工作的?

在咱们开始用Today
Extensions之前,先叫咱看看Extensions的一部分定义,以便掌握之后的科目。

  • 先是,Extensions不是独自的应用程序。Extensions必须凭让一个host
    app,下面一律吃作宿主APP,同时他们的生命周期相互独立,并且可并行接触事件。一个宿主APP可以蕴涵多单Extensions。

  • 当一个Extensions运行的下,宿主APP不会见以运行。每个Extensions都生温馨的独自进程(相当给一个微之APP)。同时,可以多单Extensions同时运行,相互间不叫影响。每次运行Extensions都是再度启航之(重复的施用相同Extensions并无见面动同样块内存)。

  • Extensions与宿主APP间不可知直接通讯,但可以尝试通过OpenURL()来打开宿主APP或利用NSUserDefaults存储和朗诵博通用的多少。

俺们数就是盖方法无对,总是想奋力的把事做对,而非是不遗余力去错自己道,从而选择对的从业!所以,就涌出了事倍而功半的现象,虽然非常用力了,效果也颇为不使预期,偏偏还非知底好到底做错了啊!

The Today Extension

好了,现在咱们准备开创一个widget,为了节省不必要的前期准备,
这里好下载到旧状态的工,记得使用VPN和改动swift
1.2 导致的语法错误。
斯老工程是一个大概的天数据展示下,so……它是索要互联网连接和一个天数据获得之API。
倘我们的天数据将从今
forecast.io这网站取得,它提供每日1000漫漫免费查询,所以在初步勾画代码前,最好先去登记并拿到属您的API
key。
Oh,还有还有,要赢得天气就需要所在城市的地理位置信息,所以我们尚欲而CoreLocation来获得地理信息。(原文略过了当下步,并提供了一个教程
,但因为极度简单用自己当此地虽增长了 (.) )

干什么未要摘重新麻烦的“七英尺”栏杆去跳呢?应该说跟友好心灵的价值观规范关于,对于什么东西又关键之正儿八经不一,而做出了一心两样决定。

Step 1:

全套准备好后,大家运行工程后该会相底的界面:

mobile.365-838.com 2

这个就算是宿主APP现在之状态了,城市名跟坐标写好了 (=.=)。
接下来,开始率先步咯!

本,也许说不定也能制造产生惊喜吗?毕竟一旦投入了大气日子,不断的召开持续改进总起天能实现的,关键就是值得不值得,这样真的就是是温馨不过好之选项了呢?

Embedded Frameworks and Code Reuse 嵌入式框架和代码用

Extensions
的生命周期是单独于宿主APP的,同时Extensions的效应应是宿主的局部机能的拉开,Extensions与宿主应有相同的意义部分,即其将会见以相似甚至同的代码和逻辑。
所以,制作Extensions的第一步,就是将通用的代码块放到一个宿主APP与Extensions都能够“拿到”的地方。
iOS 8的自制Framwork就得扶持到您!

以下是手续:

  1. 在Project
    Navigator中,点击project,然后在起的面板左下方点击”+”按钮(或选择Editor,然后AddTarget)。
![](https://upload-images.jianshu.io/upload_images/6775-d0667493f8973805.png)

这里是已经完成了状态
  1. 以开辟的面板中,选择 iOS > Framework & Library > Cocoa Touch
    Framework,然后你会盼:
![](http://www.appcoda.com/wp-content/uploads/2014/10/weather_data_kit.png)
App Extension - Weather Data Kit



名字叫 WeatherDataKit 不要搞错了,其他按项目填,然后点一下 Finish。

成功点的步骤后,你见面发觉大多单一个叫WeatherDataKit的folder和target。展开WeatherDataKit,会相只有生一个
WeatherDataKit.h 在那边,这个 .h 文件的凡在公的项目还要使 Obj-C 和
Swift
的时候使用的,作用是桥接Obj-C的条文件,当然这个类别里不要做任何操作。

每当此处大家而专注,Extension并无是力所能及统统支持有Cocoa Touch
APIs的,比如下面的几乎点:

  • 语音输入和摄像头调用
  • 于AirDrop接收数据(但会发送数据)
  • 常驻后台(Extensions的可用内存是老大没有之,同时系统内存紧张的时刻吧首先拿Extensions开刀)
  • 非克使用外含 NS_EXTENSION_UNAVAILABLE 或接近宏定义 的类似, 或
    EventKit 和 HealthKit 这种不支持Extensions的 framework
  • Access a sharedApplication object, and so cannot use any of the
    methods on that object(不懂得就句)

当今我们编译的时候如果采取上述的API将会晤遇见一些警示,可以经勾选”Allow
app extension API
only”来就是得免这些警告。(这里生只列表可以参见哪些不克就此当Extension上)

mobile.365-838.com 3

记忆勾上

吓了,接下要做的生粗略,把本来在 Weather folder 中的 “Weather Data”
移动至 WeatherDataKit folder
中,记得去改变叫挪动文件的target(三个都使)。

mobile.365-838.com 4

App Extension – Weather Group

mobile.365-838.com 5

便是此处

倒不是说选择当投资中穿梭的选择能轻松过的“一英尺”栏杆就便于,一不行就了那么吧即相当给数或投机倒把,能够再次,持续的姣好一定吗欲着意打磨,反复去举行才起或做赢得。

Extra Part!

尚记上面提过,要博得天气信息,首先要赢得到地理位置信息。原科目是用固定坐标的,这里也,我们虽自己写一个。
还是于 WeatherDataKit folder,新建一个吃 WeatherLocation 的 swift
文件。然后,在 WeatherDataKit 的 target 里添加 CoreLocation framework。

mobile.365-838.com 6

增长必要的 framework

随后就可以写代码啦:

  1. 当 WeatherLocation.swift 里,声明 WeatherLocation 的 class,它延续和
    NSObject,并且会产生 CoreLocation 的 delegate(记得先 import
    CoreLocation)。
  2. 下一场声明 CLLocationManager 对象
    ‘manager’,它好帮忙我们原则性又取得到祥的地理信息。
  3. 进而补及 CLLocationManagerDelegate 的主意:

  4. locationManager(manager: CLLocationManager!, didUpdateLocations
    locations: [AnyObject]!)

  5. locationManager(manager: CLLocationManager!, didFailWithError error:
    NSError!)
    它们一个顶住更新当前底地理位置信息,一个担负告诉你出错的情节。

  6. 末以 init() 方法里给 manager 启动。(记得上上 manager 的安装和点名
    delegate 对象)

有那简单吗?
当没有。Apple对于用户的隐情非常重视,像地理位置这种随时出卖而的信,当然如果收获用户许可才会下!
那么我们先返 Weather 这个target,找到 info 面板(或者当 Weather folder
下找到 info.plist)。
下一场上加少单价值:(在iOS 7
或事先才待一个,如果急需支持原本本子则要举行系统版本判断来开不同处理)

  • NSLocationAlwaysUsageDescription
  • NSLocationWhenInUseUsageDescription
    mobile.365-838.com 7
    以 info.plist 为例
类型记得要为 String
,内容根据自己需要填。补充完这两项后,当项目启动并在第一次使用地理位置信息的时候,系统就会自动弹出
Alert 要求获取授权,这是上面你填的信息就会显示在这个 Alert
里。(关于这两个 String
的使用场景,可以参考[Develop](https://link.jianshu.com?t=https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html))

好了,接下贴一下代码:

import Foundation
import CoreLocation

class WeatherLocation : NSObject, CLLocationManagerDelegate {

typealias WeatherLocationCompletionBlock = (latLong: String?, cityName: String?, error: NSError?) -> ()

let manager = CLLocationManager()
var latAndLong : String?
var city : String?
var block : WeatherLocationCompletionBlock?

class var sharedInstance: WeatherLocation {
    struct Singleton {
        static let instance = WeatherLocation()
    }
    return Singleton.instance
}

override init() {

    super.init()

    manager.delegate = self
    manager.desiredAccuracy = kCLLocationAccuracyBest
    manager.requestAlwaysAuthorization()
}

 // MARK: 看这里看这里
func updateLocation(completion: WeatherLocationCompletionBlock) {
    if CLLocationManager.locationServicesEnabled() {
        manager.startUpdatingLocation()
        block = completion
    }
}

// MARK: CoreLocation
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {

    manager.stopUpdatingLocation()

    var location:CLLocation = locations[0] as! CLLocation
    latAndLong = "\(location.coordinate.latitude),\(location.coordinate.longitude)"

    CLGeocoder().reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
        if (error != nil) {
            self.block!(latLong: "", cityName: "", error: error)
            println("Reverse geocoder failed with error" + error.localizedDescription)
        } else {
            if placemarks.count > 0 {
                let pm:CLPlacemark = placemarks[0] as! CLPlacemark
                if (pm.locality != nil) {
                    self.city = pm.locality
                    self.block!(latLong: self.latAndLong, cityName: self.city, error: nil)
                }
            } else {
                var otherError : NSError?
                otherError = NSError(domain: "Problem with the data received from geocoder", code: -9999, userInfo: nil)
                self.block!(latLong: "", cityName: "", error: otherError)
                println("Problem with the data received from geocoder")
            }
        }
    })
}

    func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
        println("\(error)")
    }
}

哼了,大家该发现,除了当上头列有要要贯彻的办法以及目标之外,我还加加了一个新的主意
updateLocation(completion:blockName) 和一个 block
,它的打算是查询地理位置而经过 block 的花样返回结果给调用者。
亟待小心的凡 updateLocation
方法并无兢兢业业,它并无处理结果的状态返回给调用者,这当实际开发中拿会碰到题目(比如你切莫能够管用户机器会每次都询问到结果)。

然后,在 WeatherDataViewController.swift 文件中上加一个智

func loadLocation(completionLocdLocation:(city: NSString?)->()) {
    WeatherLocation.sharedInstance.updateLocation { (latLong, cityName, error) -> () in
        weak var weakSelf = self as WeatherDataViewController
    WeatherLocation.sharedInstance.updateLocation { (latLong, cityName, error) -> () in
        WeatherService.sharedInstance.fetchWeatherData(latLong!, completion: { (data, error) -> () in
            dispatch_async(dispatch_get_main_queue()) {
                weakSelf?.weatherData = data
                weakSelf?.updateData()
                completionLocdLocation(city: cityName)
            }
        })
    }
}

loadLocation
方法里首先查询地理位置,得到结果后查询天气信息,得到气象详情后更新数据并拿当下都市名称返回给调用者,因为嵌套了
block 的关联,记得使用 weak 来吧 self 变成弱引用,避免 retain cycle
问题。

最终,我们在 ViewController.swift 里测试一下,import WeatherDataKit
(WeatherDataViewController 的 target 改变了,需要从表面引入,记得加上
framework),在 viewDidAppear 方法里丰富:

weak var weakSelf = self
loadLocation { (city) -> () in
        weakSelf?.locationLabel.text = city as? String
}

运转,等 API 返回结果,UI
更新!(如果模拟器上起谬误,记得调整模拟器地理位置的抉择项,或者指定一个地理位置)

mobile.365-838.com 8

呵呵呵呵

一旦仅是藉自己想象,以自以为是的措施去走的话,虽然接近多,结果一定也会不同了无数。毕竟,做投资来说,目的是为长久之赚取更多的收益。肯定不是情倒置,把目的及经过弄调,白忙一集市,哪肯定不是好最终想要达成的靶子。

Step 2:

入股开工作就两种植模式,一凡受祥和尽心尽力占当巨人的肩上,就假设买起一段时间来拘禁您成长概率很高的号,购买从股票,或投钱给他们控股什么。一凡是挑一个投机擅长,从长远来拘禁成功概率高的门类,通过自己慢慢试错找方向,找人,找资金,最终兑现和谐料。

Creating the Widget

主角登场~~~继续增长 target,然后命名为 Weather Widget 。

mobile.365-838.com 9

即是是

缔造好后,我们见面意识差不多矣一个 Weather Widget 的 floder 和多了一个
Scheme:

mobile.365-838.com 10

连logo都不同

而今我们来瞧一个初创的 Today widget 会时有发生什么事物:

  • TodayViewController.swift
  • MainInterface.storyboard

及平常的 ViewController 没什区别嘛~~~~但其实 TodayViewController
里已经补充加了 NCWidgetProviding 这个
protocol,乖乖的仍需上了便哼。还有久违的 didReceiveMemoryWarning
方法,看来 widget 是独时刻惨死的一声令下,大家想做的花俏的语记得做懒加载与于
didReceiveMemoryWarning 里召开释放,不然因为 widget 体验不好就是管 APP
删掉就得无尝试了。

摸索运行一下,弹出来的面板直接选 Today 就可了,然后会相底的职能:

mobile.365-838.com 11

它已经帮助你勾勒好 Hello World 了

以 Extension 和 宿主APP 都急需动用同样的代码,所以其一样如果填补加
framework:

mobile.365-838.com 12

App Extension – 添加 Framework

增补加了晚即便可以当 TodayViewController 里继承的 ViewController 改也
WeatherDataViewController ,这样就是得使用 WeatherDataViewController
的点子了。
连接下去,我们要修改 MainInterface.storyboard 里的UI,使 widget
看到底信息可知同 宿主APP 的如出一辙。

mobile.365-838.com 13

将本的 Hello World 界面改化这么

根据 Apple Extensions
Guide
的提议,widget最好是比粗的,对于详细信息要来个可适配的冲天去显得或藏。
就此灰色字体的部分会基于用户的要来展示会隐藏,这有以 stroyboard
里让一个透明的 view 所蕴藏,我们将她定义也 MoreDetailsContainer
,等下会为此到。
接下来回到 TodayViewController ……

尴尬,漏了千篇一律步,我们当延续写代码前,需要对 storyboard 或 xib 里的 UI
做适配。我们这个类别不过支持 iOS 8,所以可以放心的行使 AutoLayout 跟
SizeClass。

  1. 接触开 MainInterface.storyboard ,点击
    MoreDetailsContainer,我们需要它维持一定之万丈并且总是以脚的岗位,我们好这样设置:
![](https://upload-images.jianshu.io/upload_images/6775-f5bedeace434ac47.png)

点点这里



![](http://www.appcoda.com/wp-content/uploads/2014/10/container_view_constraints.png)
注意不要勾选 Contrain to margins
  1. 选择 Cupertino, CA
![](http://www.appcoda.com/wp-content/uploads/2014/10/cupertino_constraints.png)
改成这样
  1. 选择 100
![](http://www.appcoda.com/wp-content/uploads/2014/10/temperature_constraint.png)
改成这样
  1. 选料小箭头按钮
![](http://www.appcoda.com/wp-content/uploads/2014/10/caret_constraints.png)
改成这样
  1. 对 Mostly Cloudy 这种无确定长度的
    label,我们用为其自动根据仿改变长度,同时使和 Summy 对同。
    右键按停 Summy ,然后拖动到 Mostly Cloudy,选择 Horizontal Spacing。
![](http://www.appcoda.com/wp-content/uploads/2014/10/modify_option_a.png)
这样配置



或者在 Mostly Coudy 的 constraint 面板中,找到 Leading Space to
SUMMARY 的 contraint ,修改为 20。



![](http://www.appcoda.com/wp-content/uploads/2014/10/modify_option_b.png)
modify\_option\_b
  1. 任何组成部分参考第5步。

哼,运行一下。

mobile.365-838.com 14

当下是假数据

恐你见面发现左侧会出同一段子空白空间,我们得用底的代码把她填满:

func widgetMarginInsetsForProposedMarginInsets
    (defaultMarginInsets: UIEdgeInsets) -> (UIEdgeInsets) {
    return UIEdgeInsetsZero
}

切切实实效果好摸索看。

随之我们只要实例化 UI 上面的因素:

  1. 归来 TodayViewController,添加一个按钮和按钮方法:
    @IBOutlet weak var showMoreButton: UIButton!
    @IBAction func showMore(sender: UIButton) {
    }
  2. 长一个可变的 contraint:
    @IBOutlet weak var moreDetailsContainerHeightConstraint :
    NSLayoutConstraint!
  3. 末尾定义一个 BOOL 变量,标记 moreDetailsContainer 是否出示:
    var widgetExpanded = false

概念了后,开始写相关逻辑:

  1. Widget 初始化的当儿是从未数的,所以同样开始 moreDetailsContainer
    应该是藏身的状态:
    moreDetailsContainerHeightConstraint.constant = 0

  2. 当 showMore 方法里补充加代码:
    @IBAction func showMore(sender: UIButton) {
    if widgetExpanded {
    moreDetailsContainerHeightConstraint.constant = 0
    showMoreButton.transform = CGAffineTransformMakeRotation(0)
    widgetExpanded = false
    } else {
    moreDetailsContainerHeightConstraint.constant = 220
    showMoreButton.transform =
    CGAffineTransformMakeRotation(CGFloat(180.0 * M_PI/180.0))
    widgetExpanded = true
    }
    }
    记得在 sotryboar 里将小箭头按钮跟代码连接起来。

  3. 最后在 ViewDidLoad 方法里增长:
    temperatureLabel.text = “–“
    summaryLabel.text = “–“
    timeLabel.text = “–“
    humidityLabel.text = “–“
    precipitationLabel.text = “–“

     loadLocation { (city) -> () in
         self.locationLabel.text = city as? String
     }
    

如此widget启动之早晚就是会自行获取信息。

运行吧!

mobile.365-838.com 15

容这个箭头

纵然设由宜宾顶上海,不管而行还是盖车因飞机还能够上。但是,由于代价不同,自然所消耗精力,资金也无平等,如果您道机票太昂贵了,毕竟飞机来飞机的好,自然也发从代价过强立方面的不好。你了好选取走嘛,只需要管好团结于旅途吃罢就是尽了。

后续

先是糟翻译还有写教程呢(基本上就于胡说了),没悟出如果考虑的东西要非常多之。
随即篇教程最后还有跟 宿主APP 通过 UserDefault
来展开多少交互的有些,不过它们还是因此写很的数,这里就是非摆设了,看看后续能免可知加上再实用的道来开。

非常感谢能见到最后。

但是,这样的代价必然会浪费自己之大气年华,也会烦得狼狈不堪。这样吧不是说哪怕从未好之地方,起码好处就代价最低,不用顾虑什么风险,只要耐心反正都能够到啊。

这个以现实生活中不怕使那些显然可以烧天然气,效率又胜,污染再次小,更省时间的,偏偏觉得还是干柴做饭好吃,必须自己得上山打柴,弄回家做饭道理一样。

假如换个角度来说,如果把浪费在途中的当即段时光因故来举行自己又善于的事,也许会生的值会强多群。根本就是从未必要去举行那些难度不低,偏偏并无克给祥和再也好之挑三拣四嘛!投资被之所以选择对协调吧难度又没有,能够持续轻松过“一英尺”栏杆,意义就是介于能还快又安全的实现自己预期。

岂才会做到持续越“一英尺栏杆”呢?就非得转自己之构思模式,能够从遥远角度来举行取舍,为什么说猪在风口时,也会飞?就是因选择以起风时,恰恰又在啊位置,自然风够大一流产起来,不思竟都不便!我们如果找到这个栏杆的理也是这般,毕竟能够不断站在风口这自然啊是同等种植力量。

既然是种力量,我们自然就会由无到有,从如到大,首先就亟须得面对现实,能够对自我持有认识,知道针对团结来说什么还要紧,能够从长远看问题。其次,知道多作业之所以看起非常粗略,那是坐自己看见的都无真相,只是表面而已。

如若能够耐心潜行,随着岁月的积累,选择对属于自己“一英尺栏杆”的机会肯定必然在未来,轻拥怀中。而未是比如说就没头苍蝇在玻璃罐子里同,只是碰头及时点下,哪里碰下,就淡忘了抬头望,盖子还没有盖齐。。。

发表评论

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

网站地图xml地图
Copyright @ 2010-2018 mobile.365-838.com 版权所有