为什么我们放弃传统的iOS网络

在开始讨论之前,我将先声明免责声明:这不是您的典型的I-a-a-fant-new-thing科技博客,具有非典型,晦涩的图案。 不,这是一篇有关采用常见的基本范式并将其应用于我们以前可能从未想到过的地方的文章,或者更准确地说,是在我们忘记了它们与之相关的地方。 软件产品往往会经历总结能力成熟度模型的相同阶段,转化为软件开发。 我们通常会坚持不懈地进行尝试并进行创新。 这是因为我们不想浪费时间和金钱来为尚未得到的答案过度设计解决方案。 我们希望将精力集中在发明新事物上,因此我们会避免为重新发明轮子做任何努力。 在我开发和制造的所有移动产品中,其中一个轮子始终存在: 网络。 在MINDBODY,我们已经维护和扩展了许多不同的移动产品超过四年。 同样,大多数软件产品具有相同的根源,我们的移动应用程序也不例外。 根据年龄的不同,每种产品在某种程度上都很大程度上依赖于许多人认为是事实上的开源网络库: AF网络 Alamofire MKNetworkKit 这些功能强大且受社区支持的第三方可解决任何Cocoa开发人员的大部分联网问题-Cocoa HTTP库的全地形轮胎。 但是,我们是一家企业,以此类推完整的圆圈,不能在Peterbilt上打一堆全地形轮胎并且期望行驶很远。 多年来,我们一直在不断改进这些常见要求: 将具有不同范例和传输格式的多个API整合到一个网络会话中的能力。 在单个会话中应用不同级别的授权和其他一次性装饰的能力。 具有满足以上两个要求的具有不同主机/客户端配置的多个会话的能力。 最重要的是,我们渴望拥有SOLID基础。 建立一个全新的网络层听起来很昂贵,冒险且彻头彻尾,这在很大程度上缩小了故障间隔。 最终,这意味着我们需要从以下两个问题的明确答案入手: 我们如何设计新车轮,以及如何将东西砸在行驶的汽车上? 设计车轮 曾经有人告诉我,“只有在第三次失败之后,新架构才能成功。”作为坚定地支持这一说法的人,我将转变话题,并略谈一下Node.js。 为什么选择Node.js? 不,我不会开始赞扬JavaScript及其动态的,松散类型的,嵌套回调的荣耀。 Node.js如此流行的原因是容易和简单,通常要付出代价。 但是在某些情况下,语言和平台为出色的模式提供了基础。 在我们的案例中,我们决定招待Express.js及其中间件模式的实现。 没有花哨的全局请求管理器到处都是路由规则,序列化模式,全局请求标头,过于简化的嵌入式授权机制,缓存策略等; 没有请求操作会承担太多责任,无法尝试使摆锤向模块化方向摆动太远; 无需花三个小时阅读有关所有工作原理的文档。 网络管道架构 当简化为体系结构时,我们发现针对任何给定请求有四个主要参与者: 管道 中间件的集合 请求 响应 在我们的Swift实现中, 会话与请求管道同义。 管道中显示的任何更改或全局行为将影响该会话内的所有请求。 会话客户端使用提供的URLSessionConfiguration管理单个管道,并且它直接接受URLRequests作为输入。 这意味着,网络架构是Apple网络库之上非常薄的一层 。 客户端只是简单地通过串行队列来收集请求,通过提供的中间件链来处理它们(每个请求可以不同),最后将它们传输到URLSession。 这满足了我们的第一个要求。 中间件范式 中间件组件具有基于具体实现的职责范围,但是它们都可以做三件事: 修改请求 冻结/清空输出管道 用错误使响应短路 中间件被定义为一个简单的协议,并且可以从任何地方定义和注入自定义中间件。 […]

未经App Review批准,开发人员无法再编辑App Store描述

一夜之间,开发人员注意到iTunes Connect接口的一项无提示政策更改,Apple似乎尚未正式宣布。 开发人员无法在不制作新版本的情况下编辑其应用程序的描述,更新注释或任何其他元数据,而必须将其提交给App Review批准…… 在今天之前,开发人员可以随时更改其App Store列表的几个属性。 这包括编辑描述文本,更改“新增功能”更新说明。 现在页面上唯一可编辑的字段是隐私策略URL。 这意味着开发人员现在必须创建一个新的应用程序版本,更改元数据,然后将该应用程序提交批准。 然后,他们必须等待App Review才能使更改生效。 查看更多:https://solutionanalystsblog.wordpress.com/2017/03/10/developers-can-no-long-edit-app-store-descriptions-without-app-review-approval/

纸牌硬vs纸牌简易iPhone游戏

你喜欢纸牌游戏! 这些是最好的2游戏,具有新的接龙游戏概念。 一种游戏可以轻松获胜,而另一种则需要一些时间才能获胜。 Solitaire Easy –永远赢:在App Store上的内容 阅读评论,比较客户评分,查看屏幕截图,并了解有关Solitaire Easy – Always Win的更多信息。 下载… itunes.apple.com 纸牌硬–纸牌:在App Store上的内容 阅读评论,比较客户评价,查看屏幕截图,并了解有关Solitaire Hard – Play Cards的更多信息。 下载… itunes.apple.com 两种游戏均可从App Store免费安装到iPhone中。 在2017年的前一年,它每年的下载量超过1万。 让我们看看它的一些功能和差异。 差异 : Solitaire Easy游戏允许您将扑克牌拖放到任何色卡上。 例如,您也可以将钻石卡和十字色卡一起拖到心形卡上。 因此,这里没有颜色限制拖放扑克牌。 另一方面,在Solitiare Hard游戏中,您在玩游戏时必须注意交叉色卡规则。 这两个应用程序共有的功能如下: 它会计算总移动次数并存储时间,因此您可以衡量自己的表现 它允许您撤消最后一步。 您可以随时重新启动游戏。 您可以将您的获胜职位分享给任何社交媒体或应用程序。 您可以更改一堆图像的背景 您也可以根据需要更改卡的背面。 漂亮又酷的设计:

今日扩展:得分小部件

分数小部件是可重用的组件,可用于通过“今日扩展”显示任何游戏的分数和其他详细信息。 使用Today Extension扩展您的容器应用程序,即使您的手机被锁定,也可以让用户参与其中。 让我们看看如何使用这个很酷的小部件。 首先从下面提到的GitHub存储库下载ScoreWidget的zip文件。 pallavtrivedi03 / TodayExtension-ScoreWidget TodayExtension-ScoreWidget –可重用的代码片段,用于使用Today Extension扩展iOS应用。 github.com 在项目中导入分数小部件文件 为您的Xcode项目添加一个新目标(即今天的扩展),并导入Score Widget文件。 只需解压缩ScoreWidget.zip,然后将解压缩的文件夹放在目标层次结构下。 注意:添加文件时,请确保选择“如果需要,请复制”,然后选择扩展名作为目标。 添加分数小部件视图 将Today Extension目标添加到项目后,XCode会自动生成TodayViewController.swift和MainInterface.storyboard。 转到MainInterface.storyboard并从TodayViewControllerScene中删除Label。 我们不需要XLabel,因为我们拥有用于得分小部件视图的XIB。 接下来,我们需要将XIB作为子视图添加到TodayViewControllerScene。 为此,将以下内容添加为TodayViewController类的第一行。 var scoreWidgetView:ScoreWidgetView? 实例化声明的变量,并使用以下代码添加为子视图。 scoreWidgetView = ScoreWidgetView()。loadNib()为? ScoreWidgetView scoreWidgetView?.frame = self.view.frame self.view.addSubview(scoreWidgetView!) 这就是您的viewDidLoad()的外观。 我们完成了实例化自定义视图并将其添加为子视图的操作。 现在,让我们在“显示更多/显示更少”按钮上处理视图的放大和缩小。 处理视图的扩大和缩小 要添加“显示更多/显示更少”按钮,请在viewDidLoad中添加以下几行。 如果#available(iOSApplicationExtension 10.0,*) { extensionContext?.widgetLargestAvailableDisplayMode = .expanded }其他 { //早期版本的后备 } “ widgetLargestAvailableDisplayMode”的值决定是否可以扩展窗口小部件。 现在,您的viewDidLoad()应该看起来像 添加以上行将在我们的小部件上启用“显示更多”按钮。 接下来,当用户点击“显示更多”按钮时,我们需要处理扩展和收缩。 […]

Tooploox Hackathon:Timeploox,用于时间跟踪的Slack机器人

在Tooploox,我们在时间和物质上与合作伙伴一起工作,因为该模型使我们能够完全采用敏捷开发方法。 多年来,我们尝试了各种开放源代码和商业工具,这些工具旨在减轻与日志记录时间相关的负担和总体开销,可视化进度并生成报告。 不幸的是,即使是我们目前所依赖的当前服务(Freshbooks)也无法满足我们的所有要求,例如易于访问,工作流程快速且使用起来很有趣。 在黑客马拉松开始之前,我们有很多想法如何解决整个Tooploox团队的痛苦。 最后,我们选择了一个非常适合我们日常工作的特定概念-一个完整的(即目标)时间跟踪和报告bot,用于我们的主要沟通工具Slack。 在我们进行开发的几个小时中,该机器人“学习”了如何以丰富的方式解释和响应从任何Slack通道发出的简单命令。 例如,要记录时间,可以发出/log命令: 作为回应,您会获得简短的记录时间摘要: 可以通过/log view命令在任何给定的时间点查看和删除条目: 结果是: 我们的团队还设法构建了一个配套的iOS应用程序,该应用程序至少在黑客马拉松的范围内,用于查看各种Slack用户记录的时间报告: 从技术角度来看,我们决定使用可快速开发和部署原型每次迭代的工具和平台。 在后端,我们使用了Node.js(ES6,Express.js,Mongoose),Heroku,MongoDB(通过附加组件)和Slack API,而移动应用程序是使用Storyboard进行Swift编写的(用于快速UI原型制作)很少有开源框架,例如Alamofire和Charts。 尽管有时会遇到颠簸,但为iOS应用程序和机器人本身构建API通常非常简单和有趣。 我们在MongoDB插件上遇到了问题,不得不在Slack部分处理一些奇怪的消息格式选择,例如在父JSON结构中编码为原始字符串的JSON内容。 由于黑客马拉松赛仅进行了两天,因此我们只需要为我们的iOS配套应用选择最重要的功能。 我们得出的结论是,使用此应用程序的主要目的是检查我们或我们的同事条目。 因此,在产品设计团队的帮助下,我们准备了用于摘要视图的设计,然后开始工作。 您可以在上面的屏幕截图中看到结果。 该视图非常简单,最困难的是日历视图,我们免费获得-我们使用了强大的FSCalendar控件。 最后但并非最不重要的是,团队。 我们很幸运,并设法组建了一支由产品设计师,全栈和iOS工程师组成的团队。 这意味着我们有足够的原始马力来解决我们想在合理时间内解决的难题。 就目前而言,该机器人为更大的事物奠定了良好的基础,并有望在不久后将其推向新的高度。 总而言之,一起破解项目并制定各种怪癖很有趣! 由Krzysztof Tarnowski和Karol Wieczorek撰写。

了解您的下载,按关键字关键字

在Quora的ASO线程中,我们看到有人问,Google Play或iOS App Store中是否有一个工具可让您查看每个应用程序有多少下载? 可悲的是,所有答案基本上都说:“不,但那不是很棒”。 令人高兴的是,我们很自豪地说“是”-实际上,有一个工具可以帮助您做到这一点。 昨天,我们在您的信息中心宣布了“每个关键字的下载估算值”功能。 要查看其工作原理,请看上面的示例应用程序VPN Hero Shield。 他们为其排名的一些关键字包括“ vpn”,“ vpn free”和“ proxy”。 现在,只需转到信息中心,您就可以确定哪些关键字为您带来了最多的下载量。 惊喜,惊喜—“ vpn”获得了VPN Hero Shield下载量的64%。 另一方面,“代理”的表现很差。 现在,我们知道您可能会遇到一些问题,即“如何将这种出色功能应用于我自己的应用程序?”。 让我们跳进去。 您的数据向导如何计算每个关键字的下载估算值? 好吧,我们无法透露所有信息,但是由于过去两年中我们拥有超过400万个应用程序的深层数据,并且每天都会更新每个基准测试-我们的敬畏而辛勤的数据科学家使用现有信息并通过我们的算法对其进行了过滤,从而得出以这些百分比。 这是真实数据吗? 不,这是一个估计,但是是一个非常准确的估计(请参阅Incipia上个月关于移动操作被评为最准确的ASO工具排名第一的研究)。 不幸的是,没有人可以提供您实际的数据,但这是次要的事情! 在哪里可以找到它? 要使用每个关键字的下载估算值,请转到ASO Intelligence下的“关键字分析”部分。 向下滚动,直到到达关键字列表,它是第三个标签。 瞧! 或者-您可以单击此链接。 如何将估算数据应用于自己的应用? 这将有助于找到您应在ASO和广告中使用的最有效的关键字,从而可能提高排名,下载量和收入。 现在,您可以停止浪费时间在无法获得实际结果的关键字上。 丢弃无效的文件,并获得所需的下载文件。 查看每个关键字的下载估算!

VIPERtasarımpaterni nedir?

吉里斯 Apple iOS的MVC模式,可以帮助您解决MVC的问题。 1996年MVC足球比赛将在MUL 1996举行。 Microsoft网络模型Web窗体Web窗体MVC模式2009年窗体的窗体。 iOS的MVC模式的MVC模式的ihtiyaçlarıkarşılamamayabaşladı。 位置视图控制器的位置已过时。 业务逻辑模型业务模型模型业务层数据库—数据模型sade hale getirildi。 她的母亲是孩子,是孩子,是孩子,是孩子,是孩子,她的孩子,孩子,孩子,孩子,孩子,孩子,孩子,孩子,孩子。 an MVC haricinde MVP,MVVM和VIPERtasarımpaternleri var。 在iOS上的应用程序在VIPER上运行的时候,会出现inceleyelim。 VIPER mimarisi nelerdenoluşur? VIPER mimarisiadını视图,交互者,演示者,实体路由器(线框)’ılkharflerindenalıyor。 Bukavramlarınneolduğunakısacabakalım。 视图: VIPER mimarisinde视图被动演示者演示者被动演示。 HangiiçeriğingösterileceğiView’ebağlıdır。 Kullanıcıactionlarıpresenter’ayönlendirir。 交互器:业务逻辑işlemlerininyapıldığıkısımdırveuygulamanınomurgasınıoluşturur。 Bu katmandayapılanişlemlertamamen UI danbağımsızolmalıdır。 主持人:主持人esas olarak查看il ilgili logic’iiçerenkoduiçerir。 用户交互作用的用户数据查看用户交互作用。 查看ile Interactorarasındabirköprügörevigörür。 Bu katmanda视图ile ilgili veyauygulamanın商业kurallarıylailgili kodbulunmamalıdır。 实体:交互模型tarafındankullanılan模型nesneleriniiçerir。 Entity’lerin sadece Interactortarafındankullanılmasıçokönemlidir。 Interactor asla演示者层’实体模型lerinigöndermez。 路由器: Hangiekranlarınne zamangösterileceğinibelirlendiğiuygulamageçişakışınbulunduğukatmandır。 […]

iOS应用内购买和订阅

真的很简单。 看一下下面的代码。 让我们来看看它。 一些关键概念是: SKPaymentQueue : 保留所有事务以进行进一步处理的队列 SKProduct :在Itunes中声明的产品与所有可用信息联系在一起 SKPayment :购买产品的意图 SKPaymentTransaction :有关SKProduct的事件 SKProductRequest :请求获取有关提供产品ID的SKProducts的信息 SKProductResponse :包含所需产品的响应。 它由两个列表组成:产品和invalidProductIdentifiers。 第一个将包含成功获取的SKProducts,第二个将包含未能与SKProduct相关的所有标识符。 如果您获得无效的标识符,这是一个故障排除列表,可以帮助您。 确保合同,税务和银行信息已完成 确保正确拼写ProductID 确保AppID是显式的(没有通配符(*)) 确保配置文件是正确的配置文件 确保在产品说明中启用了待售清算选项 确保产品处于批准状态 确保不拒绝对App Store的最后一次App评论 现在,首先,通过以下几行,您可以轻松地创建一个SKProductRequest。 let request = SKProductsRequest(productIdentifiers:productIDs) request.delegate =自我 request.start() 由于以下方法是回调,因此请确保实现SKProductsRequestDelegate。 func productsRequest(_请求:SKProductsRequest,did接收响应:SKProductsResponse) 在那里,您将获得适用于您的应用程序的所有SKProducts。 要进行购买并创建SKPayment。 让付款= SKPayment(产品:产品) SKPaymentQueue.default()。add(付款) 确保在允许用户进行购买之前,始终要获取产品。 这些SKProducts将在其中局部化价格,因此您应该显示它。 这样可以确保您始终将应用程序中的数据始终保持最新,因为应用程序中的价格错误可能会导致Apple将其从App Store中删除。 您可能还会在流程中注意到“ 外部事件”部分。 交易可以在您的应用程序外部发生。 假设您的用户在系统设置中更改了其订阅类型,或者您的延期交易获得了用户父母的批准,那么除非您期望它们,否则您将无法告知。 因此,始终在AppDelegate中,在您的应用程序开始时,将该应用程序订阅到PaymentQueue。 这样,您将确保您不会错过任何事件。 现在,有时该帐户将无法使用。 […]

Swift 3.0中的Any vs.AnyObject

当我在第一次解析JSON数据时遇到这两个类型别名时,我不知道如何正确区分或实现它们。 那是什么 Any和AnyObject是Swift中的两个特殊类型,用于处理非特定类型。 根据Apple的Swift文档, Any 可以代表任何类型的实例,包括函数类型和可选类型。 AnyObject 可以代表任何类类型的实例。 好的,很简单-所有类型都使用Any ,Class类使用AnyObject ,对吗? 为了了解它们在代码中的实际行为,我决定在Playground中与它们一起玩。 任何人都允许我使用不同类型的混合函数,包括函数和非类类型,例如Int,String和Bool。 根据文档,此数组中的元素是作为值类型的Structs,因此从理论上讲, AnyObjec t在这些情况下不起作用。 为了验证这一点,我尝试使用AnyObject包括String和Ints,这是Swift中的值类型。 不出所料,编译器向我抛出一个错误,指出元素与数组中的AnyObject类型不符 。 知道了! 然后,当我尝试遵循编译器的建议时,发生了一件奇怪的事情: 刚刚发生了什么?! 如何通过将每个元素显式转换为AnyObject来在整数和字符串上使用AnyObject ? 然后,我将anyObjectArray打印到控制台中。 在我看来, Hi元素显然看起来像是一个字符串,但是在Swift中却没有像普通的String值一样引号! 接下来,我使用for-in循环打印每个元素,以检查其实际类型,而不是AnyObject的强制类型。 首先,我使用了is运算符来查看元素是否为Swift Struct类型。 它是String类型的! 那么如何将其转换为AnyObject呢? 同样,Swift中的字符串是结构,而不是类类型。 因此,从理论上讲,我不应该将它们转换为AnyObject 。 我完全感到困惑,决定对它做更多的实验。 这次,我使用了Objective-C类型的NSNumber和NSString来检查每个元素的类型。 等等, 嗨也是NSString,数字元素是NSNumber! 而且……它们是Objective-C中的引用类型! 这是为什么Hi在控制台上没有引号的原因吗? 我写了一些下面的代码,看我的假设是否正确。 🔎 已确认! 现在, 转换为数组中AnyObject的元素是Objective-C的类类型:NSString和NSNumber。 那么……幕后到底发生了什么? 我继续深入研究该主题,并从文档“ 将Swift与Cocoa和Objective-C(Swift 3.0.1)”中找到了最合理的答案。 作为与Objective-C互操作性的一部分,Swift提供了使用Cocoa框架的便捷高效的方法。 Swift会自动将某些Objective-C类型转换为Swift类型,并将某些Swift类型转换为Objective-C类型。 可以在Objective-C和Swift之间转换的 类型 称为 […]

关于两个图书馆的故事

这不是关于您的典型库的故事,而是关于编程中的库的故事。 在这种情况下,库是程序可以使用的预编译模块的集合-无论是函数,变量,类还是数据结构。 通常,库对于存储经常使用的模块很有用,因此当程序运行所述模块时,并非每个程序都必须显式链接某个模块。 有两种类型的库,静态库和动态库。 在深入探讨关键区别之前,对您来说,重要的是要了解程序(在这种情况下为C程序)的编译方式。 编译分为四个步骤,其中最后一个阶段是链接器。 链接器采用在上一步中创建的程序的目标代码以及该函数使用的函数的所有其他目标文件,并创建一个可执行文件。 让我们看一下包含静态库的程序和包含动态库的程序的链接阶段的两个示例。 示例—静态库 您创建了一个程序calculation_static.c ,该程序运行函数get_product(int a, int b) 。 编译后的汇编程序短语之后,您的函数现在将转换为目标代码。 作为链接阶段的第一步,链接器将使用calculation_static.c的目标代码,并使用该目标代码生成可执行文件。 但是等等,链接器将在所有库中搜索get_product(int a, int b)函数。 链接器找到它后,它将复制get_product(int a, int b)的目标代码,并将其粘贴到get_product(int a, int b)为get_product(int a, int b)创建的可执行文件中。 优点:静态链接的最大特点是可执行程序,如果它是第一次运行,它将始终运行。 该代码不会被破坏。 缺点—例如,如果有多个函数,假设我们的calculation_static.c包含100个函数,而我们包含另一个C程序calculation2_static.c ,其中包含200个函数,那么您需要在其中包含所有300个函数的目标代码。您的可执行文件。 假设您是通过静态链接生成可执行文件的,而用户则将这个可执行文件用于其程序。 几个月过去了,包含get_product(int a, int b)函数的库的创建者完全更改了该函数。 这就是问题所在,用户几个月前使用的可执行文件具有旧的get_product(int a, int b)函数,而不是新版本。 用户将不得不使用该库再次编译原始C程序,并获取该可执行文件以更新其版本。 本质上,每次更新库时,您都必须重新编译程序。 如何创建-要创建静态库,最基本的工具是名为“ ar”(档案)的程序。 该程序可以修改静态库中的目标文件,列出目标文件的名称以及其他各种内容。 ar rc libraryName.a filename.o filename2.o filename3.o […]