Tag: swift

苹果WatchKit ile ListeOluşturma

Merhaba。 苹果公司的“ Abi iyigüzeldeTürkçebir kaynak yok yaa”苹果手表公司的手表。 她的语言是“你好,世界”,它是世界级的。 Ancak bizbugünbuduvarlarıyıkıp,adete bir devrimyapıp-böylegereksiz bir heyecanla- iOS’danaşinaolduğumuzUITableViewörneğiyapacağız。 Ancak WatchuygulamasıgeliştirirkenUIKit yerine WatchKitkullanacağız👽。 Hemenbaşlayalım。 观看ProjesiOluşturma Bir Apple Watch手表,手表和手表 。 Bizim erimizdehalihazırdabir iOSuygulamasıolduğuvarsayılacak。 Bizimistediğimiziseuygulamamızın观看versiyonunu yapmak。 Adım1: UygulamamızseçiliykenResim 1.0 ‘ 文件>新>目标… adımınlarınıizleyerek yeni bir观看projesioluşturmayabaşlıyoruz。 Daha sonra Resim 1.1’deki gibi WatchKit App应用了 。 Bu noktada projeye bir isim vermen gerekiyor。 Ben WatchTest专用语。 […]

戴夫·托马斯(Dave Thomas)的数据处理卡塔(Kata)的快速解决方案(3)

戴夫·托马斯(Dave Thomas)的数据处理卡塔(Kata)的快速解决方案(3) 保持干燥 在第3部分中,要求我们从第1部分和第2部分中干燥(不要重复自己)代码。我的完整解决方案可以在这里找到。 拿起先前编写的两个程序,并尽可能多地分解出通用代码,剩下两个较小的程序和某种共享功能。 第1部分和第2部分中的分配非常相似。 每一项都要求我们加载文件,将文件的文本提取到表中,清理每一行,选择我们感兴趣的列,然后查找并打印两列之间的差异最小的行名。 我将Dave的说明解释为“留给您两个小程序”,意味着我应该创建我的“ Executor”结构的两个版本,一个用于天气,另一个用于足球数据。 在一个实际的项目中,我将合并为一个结构,该结构接受闭包作为两种数据类型之间不同的每种方法的参数。 考虑到我略微潮湿的“法律法规”方法,有两种方法需要重构。 removeUnneededColumns() 由于每个文件都有我们需要使用的不同列,因此不再可以对其进行硬编码。 我的方法是包括一个validColumnIndexes:[Int]参数。 然后,我们遍历每个索引并返回该行中单元格的映射。 静态函数removeUnneededColumns(fromTable表:[[String]],validColumnIndexes:[Int])-> [[String]] { 返回table.map {(行:[String])在 返回takeNeededColumns(行:行,有效列索引:有效列索引) } } 私有静态函数takeNeededColumns(行:[String],validColumnIndexes:[Int])-> [String] { 返回validColumnIndexes.map {row [$ 0]} } 。评估() 我们的评估方法也需要更改,因为在接受特定类型的数组之前。 为了解决这个问题,我创建了WeatherRecord和FootballResult都符合的DifferenceCalculatable协议。 协议差异可计算{ var名称:字符串{get} var差异:Double {get} } 这样一来,我们就可以创建一个通用的评估方法,该方法的类型必须限制在DifferenceCalculatable中,从而可以访问.difference和.name, 静态函数评价(项:[元素])->字符串? { 令lettDelta = items.minElement {$ 0.difference <$ 1.difference} 警卫队让名字= minimumDelta?.name其他{返回nil} 返回“ \(名称)” } 符合DifferenceCalculatable意味着我必须将WeatherRecord的let […]

UIDatePicker + UITextField

@IBAction func textFieldEditing(sender:UITextField){ 让datePickerView:UIDatePicker = UIDatePicker() datePickerView.datePickerMode = UIDatePickerMode.Date sender.inputView = datePickerView datePickerView.addTarget(self,action:#selector(AddTableViewController.datePickerValueChanged),forControlEvents:UIControlEvents.ValueChanged) } func datePickerValueChanged(sender:UIDatePicker){ 让dateFormatter = NSDateFormatter() dateFormatter.dateStyle = NSDateFormatterStyle.MediumStyle dateFormatter.timeStyle = NSDateFormatterStyle.NoStyle dateTextField.text = dateFormatter.stringFromDate(sender.date) } 快速使用datepicker作为uitextfield的输入

为什么不能将IBInspectable与枚举一起使用?

我记得当我在2014年看到WWDC的IBInspectable和IBDesignable时 ,我的反应是: 太神奇了,现在我可以创建一个组件并在Interface Builder中查看结果并配置它,这是设计人员可以使用的一个很棒的功能。 完善! 不。 要了解IBDesignable和IBInspectable ,请参阅我的另一篇文章– 什么是IBDesignable / IBInspectable? [1]。 尝试与IBInspectable一起使用枚举 如果尝试创建像下面的代码这样的枚举并将其与IBInspectable属性一起使用,您将看到它不起作用。 枚举DateFormat:Int { 案例短// 05/20/2016 案例Medium // 2016年5月20日 案例全// // May 20,2016 11:10 AM } @IBDesignable 类CustomLabel:UILabel { @IBInspectable var format:DateFormat = .Short { didSet { //更新标签 } } } IBInspectable对类型有一些限制: Int,CGFloat,Double,String,Bool,CGPoint,CGSize,CGRect,UIColor和UIImage 。 我认为IBInspectable不支持枚举,因为正如Swift编程语言所说: “使用枚举创建枚举。像类和所有其他命名类型一样,枚举可以具有与之关联的方法。” [2] 因此,枚举不仅是一个简单的枚举,而且可以为(例如)创建更多的枚举: 公共枚举DateFormat:Int { 案例短// 05/20/2016 案例Medium […]

Swift中的关联类型

动机 可重用性是软件开发中的重要组成部分。 我认为,软件体系结构中最重要的考虑因素之一就是即将推出的功能的实现时间。 我经常有片刻,然后躺在床上,直到实施了该死的功能后才入睡。 因此,快速的实施时间可以为我节省大量的睡眠时间(这是我绝对需要的)。 继承是重用超类功能的一种方法。 但是事情会迅速发展,随之而来的是复杂性的增加。 幸运的是,我们在Swift中有了面向协议的方法。 但是协议必须是通用的,以便将其定义重新用于不同的类型。 类允许我们指定通用参数。 协议为我们提供了“关联类型” 。 实际示例:用于CoreData处理的CRUD协议 我想为我的CoreData实现创建一个协议。 这将是常见的CRUD (创建,读取,更新,删除)功能。 没有通用协议,我必须在所有地方都使用NSManagedObject,这真的很不舒服,因为我有Xcode生成的子类。 我的实体是: TaskMO和ItemMO 。 我都需要他们的经理班。 对于TaskMO,协议定义必须匹配一次,对于ItemMO,协议定义必须匹配一次。 可以使用“ associatedtype ”关键字来实现。 协议持久{ 关联类型实体 } 如您所见,实体只是一个占位符,而不是具体类型。 具体类型将仅在实现中指定。 使用约束来缩小类型 Persistable协议使我们能够处理CRUD功能。 但是我要确保将其用于CoreData。 我们可以通过向我们的关联类型添加约束来确保这一点。 就我而言,我只想允许在NSManagedObject子类上使用。 此步骤与通用参数非常相似。 协议持久{ relatedtype实体:NSManagedObject } 完整协议如下所示: 编写实现 现在按照您习惯的方式实现类型。 名为“类型推断”的编译器功能会自动检测具体类型的定义。 因此,我们不必明确指定它。 煮咖啡机 凉。 我们创建了一个通用的可重用协议。 但是,让我们深入一点。 我想制造一台咖啡机。 不只是基本的黑咖啡。 我想要一杯很棒的拿铁玛奇朵。 首先,我指定成分: 我的咖啡由主要的咖啡成分和某种牛奶组成。 我将协议命名为“ Drinkable […]

基于合同的软件架构模式

再次简化软件架构 营销中最重要的规则之一就是倾听其客户需求。 让我们考虑MVVM架构中View客户端的真实需求,注册模型变更通知,以便为他们提供最佳的编码体验,并定义一个架构合同,该合同将满足他们的需求,以严格遵守合同规则。 定义这组需求是为了通过减少此通知调用的外部可变性来减少软件的复杂性:为了获得流畅的体验,当上下文完全由以下内容确定时,只有一种可能的方法可以调用目标函数数据和线程的观点。 此外,该合同应完整并考虑与模型的所有交互:这样,合同就保护了目标功能背后的代码不受应用程序其余部分的影响。 与其编写复杂的代码来管理所有意外的可能情况以解决所有可能的执行情况,不如通过设计减少到唯一的情况并通过合同来强制执行,来减少可能的情况数量。 实施名义上的方案就足够了。 确定每个客户的需求 从市场细分的角度来看,有几种类型的客户: 1)查看内容客户端: 视图内容客户端是视图控制器的功能,负责基于某些模型属性渲染视图。 客户端需要通过其视图模型从模型中读取一组属性:因此,当这些读取属性发生更改时,必须通知客户端。 当所有读取属性都稳定时,客户端要求该通知仅在主线程事件循环中一次 同步发生。 稳定意味着这些读取属性在事件循环结束之前不会更改。 这样可以保证所显示的内容与模型的当前状态完全匹配,而不是其先前状态的过时副本。 客户端可能还需要编写一些模型属性,其他View Content客户端将使用这些模型属性。 在属性写入后,这些订阅的View Content客户应收到其通知。 书面财产应作为合同的一部分。 不允许客户读取或写入不属于合同一部分的任何财产,因为这可能会破坏其他客户的“财产稳定”规则。 在渲染视图时,所有这些都发生在主线程中。 客户端还要求在事件循环结束之前不得删除其视图控制器,这意味着将在接收到此通知之前执行视图层次结构渲染。 该客户端还需要独立于模型对象的存在而注册模型属性,以便与模型对象创建/删除分离:每个模型属性均由源自根模型对象的唯一键路径标识。 这组需求是通知合同的基础: “当这组现在稳定的READ属性中的至少一个发生更改时,我只希望同步地被通知一次,并且我可以读/写其中一些WRITE属性。” 因此,通知调度程序应基于这些联系来计算模型属性之间的依赖关系:如果合同读取A并写入B,则B依赖于A,这将创建模型属性顺序。 因此,通知调度程序应将合同级别计算为读取集的最高属性级别,并按此顺序进行调度。 2)查看层次结构客户端: 视图层次结构客户端是一种视图控制器功能,负责基于一组模型“视图层次结构”属性,通过创建/删除子视图层次结构来修改其子视图层次结构。 该客户端不应向其子视图控制器提供模型属性,而应仅向子视图控制器用于从模型中获取其模型属性的不可变配置数据。 由于视图层次结构更新将从根到叶发生,因此每个视图层次结构客户端均应提供与其层次结构级别相同的优先级编号: 根视图控制器=优先级1 其子级=优先级2 它的子孙=优先级3 等等… 通知调度程序将首先按优先级顺序发送基于优先级的通知,然后再发送与数据相关的通知(例如:查看内容)。 视图层次结构客户端可以写入任何不稳定的视图内容或视图层次结构属性,即不属于优先级相等或较低的优先级合同。 因此,合同如下: “当该组现在稳定的READ(视图层次结构)属性中的至少一个发生更改时,我希望仅在此优先级级别上仅被同步通知一次,并且我可以读/写任何非稳定属性。” 3)标准化,协调,计算数据客户端: 规范化客户端负责解决跟随模型写事务的模型中的任何不一致问题。 协调客户端负责在高层确定应用程序/文档的视图层次结构和上下文,并设置视图层次结构属性。 计算数据客户端负责计算一组属性,这些属性可以由多个视图模型共享,并且应在呈现视图层次结构之前进行计算。 这些客户端具有基于优先级的合同,带有硬编码的负优先级,可以在View Hierarchy客户端之前安排它们。 归一化=优先级-3 协调=优先级-2 计算数据客户端=优先级-1 查看层次结构…优先级为正 查看内容…无优先级/数据驱动 我们可以为客户提供优质服务吗? 当前有许多架构模式被大肆宣传,很明显,它们都试图满足其中一些需求。 据我所知,最接近上述需求的是单向Elm […]

iOS中的NSNotificationCenter

NSNotificationCenter就像中央枢纽,在该枢纽中,应用程序的任何部分都会发布和接收通知 注册 注册n次通知,您将收到n次通知 debugDescription 从iOS 9+开始, 现在,从调试器进行打印时,NSNotificationCenter和NSDistributedNotificationCenter将提供调试描述,该调试描述将列出所有已注册的观察者,包括已被调零以帮助调试通知注册的引用。 该数据仅在断点期间有效,因为基础存储必须考虑多线程环境。 传递给addObserver方法族的名称或对象为null的通知通配符注册将在调试描述中显示为*。 观察者 addObserver(_:selector:name:object 🙂 使用观察者,通知选择器和可选条件(通知名称和发送者)将条目添加到接收者的分发表中。 NSNotificationCenter对其观察者的引用微弱 常规通知中心在发布通知的线程上传递通知 addObserverForName(_:object:queue:usingBlock 🙂 使用通知队列和要添加到队列的块以及可选条件:通知名称和发送者,将条目添加到接收者的调度表中。 此方法返回的是充当观察者的不透明对象,并且NSNotificationCenter拥有对该对象的强引用 避免强烈捕获块中的对象。 请参阅NSNotificationCenter,其中包含被认为有害的块 什么时候注销? 我们的想法是在我们不需要接收通知时立即注销。 大多数时候,这是我们的`deinit` 请参阅注销观察者 在取消分配观察通知的对象之前,它必须告诉通知中心停止向其发送通知。 否则,下一个通知将发送到不存在的对象,并且程序崩溃 iOS 9+ 参见OS X 10.11和iOS 9发行说明Cocoa Foundation Framework 在OS X 10.11和iOS 9.0中,NSNotificationCenter和NSDistributedNotificationCenter将不再向可能释放的已注册观察者发送通知 这意味着不需要观察者注销其释放方法 然而, 当不再使用时,通过-[NSNotificationCenter addObserverForName:object:queue:usingBlock]方法的基于块的观察者仍然需要取消注册,因为系统仍然对这些观察者保持强烈的引用 所以我们必须在返回的`observer`对象上调用`removeObserver` https://gist.github.com/onmyway133/9ce293862999c3e5eb205d33923b881e 同步性 通知中心将通知同步发送给观察者。 换句话说,发布通知时,控件不会返回到发布者,直到所有观察者都收到并处理了通知 如果您在向大量观察者发布通知时遇到性能问题,请考虑使用 dispatch_after 许多NSNotificationCenter NSNotificationQueue NSNotificationQueue –排队方法立即返回 –与运行循环模式关联 […]

键盘处理

键盘是否覆盖文本框? 当您不知道如何解决该问题时,您会觉得无用吗? 你的老板是白痴吗? 答案在本文中! 提示:触摸屏幕时,键盘应隐藏。 我们初始化一个点击手势识别器,并连接到dismissKeyboard方法。 检测键盘动作 第一步是检测键盘是否显示或隐藏。 我们使用NotificationCenter来捕获操作。 这是Apple编写的NotificationCenter文档。 键盘出现时,将调用keyboardWillShow方法,键盘消失时,将调用keyboardWillHide方法。 处理键盘框架 让我们在类的顶部声明一个称为keyboardHeight的变量。 还有一些魔术 这里是控制器的所有代码。

Swift中MVVM的面向协议的技巧

嗨伙计。 最近,MVVM已成为iOS应用程序的某种标准架构。 它提供了很好的关注点分离,格式化数据的好方法以及使用诸如RxSwift之类的框架的出色视图绑定机制。 在这篇文章中,我将提供一些技巧来简化该模式的实现。 可重用使视图变得简单 使用MVVM,视图与体系结构其余部分之间的分离非常清晰。 视图包括UIViewControllers及其出口。 实际上,实例化View变得越来越重要,特别是因为诸如Coordinator之类的模式越来越受欢迎。 在本文的其余部分中,我们将假定您正在实现这种体系结构。 Reusable是一种API,它带有对UIViews和UIViewControllers的便捷扩展,可以方便地以类型安全的方式实例化它们。 这是GitHub存储库:可重用。 它是与Carthage,CocoaPods和SPM兼容的轻量级API。 不使用它带来的幸福🖖真可惜。 基本上,Reusable提供了mixins(具有默认实现的协议),一旦您使它们符合适当的协议,它们就会向UIViews和UIViewControllers添加实例化函数。 在使用Coordinator模式时,有时需要实例化UIViewControllers并将其传递给ViewModels。 幸运的是,因为可重用在此方面有很大帮助。 这是将Reusable用于UIViewControllers实例化所需要做的事情: 为每个UIViewController创建一个Storyboard文件(当然,如果在同一个Storyboard中可能有多个UIViewController,但是为了简单起见,我们将仅考虑一个UIViewController) 将UIViewController设置为场景中的初始ViewController 创建一个UIViewController文件,其中ViewController类名与Storyboard文件名相同。 例如,如果故事板文件名为“ SettingsViewController.storyboard”,则UIViewController类将命名为“ SettingsViewController” 使UIViewController实现“ StoryboardBased”协议 就是这样。 现在,您可以使用单行代码实例化ViewController: 最酷的是, settingsViewController的类型是SettingsViewController ,不需要强制转换语句。 实际上,基于Storyboard的协议非常简单。 让我们深入了解一下: 基本上,它的作用是为实现该协议的每个UIViewController提供静态的“实例化”功能。 此函数返回UIViewController的实例。 由于“ Self”是函数的返回类型,因此类型推断可确保我们不必强制转换结果。 我强烈建议您深入研究可重用。 从类型安全的方式从Xib实例化UIView或使UITableViewCells出队时,这也将很有帮助。 面向协议的ViewModel 在当今的应用程序中,类似协调器的体系结构很常见,尤其是当与MVVM模式组合时。 这就是为什么我希望首先谈论Reusable的原因。 但是我发现有一个技巧非常有用,并且是可重用的补充。 它非常适合面向协议的方法中的MVVM模式。 这个想法不仅是为了简化UIViewControllers的实例化,而且是提供一种很好的方式来传递它们相关的ViewModels。 让我们写一个协议来定义拥有ViewModel的含义。 现在,我们可以将其与StoryboardBased混合使用,并提供一个静态函数,该函数以ViewModel作为参数实例化UIViewController。 条件扩展是一个非常强大的工具。 结合了“ StoryboardBased”和“ UIViewController”的“ where”语句使Self.instantiate函数可用,因此我们只需要将此调用包装在另一个设置UIViewController.viewModel属性的静态函数中即可。 假设我们有一个符合ViewModelBased协议的MyViewController: 使用ViewModel进行实例化将非常容易: 让我们进一步了解ViewModel抽象 到目前为止,我们仍然必须实例化ViewModel并将其提供给View。 […]

展开Swift 3.0中的可选值-Guard Let vs If Let?

当以iOS开发人员的身份编写代码时,您将需要灵活性:var或let,类或结构,集合或数组。 不管它的功能是否不同,要想成为一名更高效的程序员,做出选择都至关重要。 展开可选值也不例外。 解包可选值时,我们中的许多人都对可选绑定和“ if let”语法约定非常熟悉。 “ if let”允许我们仅在有值的情况下安全地解开可选值,否则,代码块将不会运行。 简而言之,当值存在时,它的重点是“真实”条件。 然后,我可以一直使用“ if let”吗? 我为什么还要烦恼使用警卫let语句? 好吧,让我们通过检查下面的代码来决定原因。 在此示例中,我们从iOS设备上的文本字段中获取用户输入以制作完整的故事。 用户输入是:名字,年龄,城市和职业。 在这里,我们得到了可选值,必须将它们解开后才能正确显示在标签上。 我们可能会通过编码如下代码立即想到“ if let”来解开那些可选值: 您如何看待此代码? 它运作良好,但请看一下嵌套条件的冗长行。 如果我们需要用户提供更多信息怎么办? 我们应该继续写嵌套条件吗? 看起来很乱。 我们还可以将“ if let”与提前退出结合使用,如下所示: 它看起来比以前的要好一些。 但是,由“ if let”解开的值只能在if块的范围内使用。 在if块之外,必须使用!再次强制将其拆开。 似乎效率不高。 现在,让我们来看一下使用“ guard”语句的代码。 另一方面,“后卫”声明使我们的代码更具可读性。 可读性和易于维护非常重要,尤其是与其他程序员一起工作时。 如上面的“ if let”示例中所示,“ guard”语句有助于避免众多嵌套条件的复杂性。 与“如果让步”不同,“后卫”声明使早期退出成为可能,并着重于带有错误的负面案例,而不是正面案例。 这意味着如果不满足条件,我们可以通过运行卫队的else语句来测试否定情况,而不是先等待嵌套条件通过。 但是,使“后卫”声明真正脱颖而出的原因在于,在其余的冷块中仍保留有未包装的可选值。 这意味着当条件通过时,可选值将被解包,并且即使在条件之外也无需强制再次对其进行拆包即可使用。 无需像我们在“如果放手”中那样提前退出就强行打开它们。 请参见下面的代码。 需要注意的一件事:每个“ guard”语句必须始终通过退出其所在范围来转移控制权。更具体地说,如果在功能中使用“ guard”,则通常将“返回”,而在循环中,则将“中断” ”或“继续”。 (注意:“ break”和“ […]