Tag: 可可触摸

设置一个Xcode项目以开发可共享通用代码的Cocoa和Cocoa Touch框架,并为MacOS和iOS应用程序提供可重用和可重新分发的UI和非UI组件

缺少这样的教程,或者至少当我第一次尝试执行标题(尽可能长,但尽可能短)时,自己还没有找到。 我来到了来自C#编程的Apple开发生态系统,只是试图通过新的(很有希望的)macOS和iOS目标扩展我公司已经为Windows和Web开发提供的产品集(主要是组件库)。 由于我必须通过尝试和重试来学习所有内容,而且这并不容易(至少不应该像恕我直言,这本来应该如此简单),所以我认为写下已建立的步骤并没有什么害处(随后一些屏幕截图),也许他们也可以帮助其他人-谁知道? – 在将来。 因此,让我们开始吧。 一个项目,多个目标,没有显式工作区 我了解到的第一件事是(与.NET世界中Visual Studio解决方案通常将更多项目分组的情况不同),我不需要Xcode工作区来对多个项目进行分组。 仅仅是因为我不需要多个项目。 因为单个Xcode项目可以定义多个目标,所以每个目标都有其自己的类型和目标,并且每个目标都具有针对特定平台(例如macOS或iOS)构建的二进制文件。 (但是,顺便说一下,无论何时创建项目,无论如何都会为其创建内部工作区。) 在我的研究期间,我也没有发现对通用的跨平台层的真正技术需求(尽管我曾经习惯于在.NET中开发共享的跨平台类库。)仅仅是因为Xcode中的每个源代码文件项目可以是其一个或多个目标的一部分,而无需任何源代码重复,并且目标可以根据需要完全自定义。 因此,让我们在Xcode中创建我们的第一个项目。 我们可能会尝试从一个更具体的项目类型开始,但是我发现如果首先选择一个Empty模板(从“跨平台”选项卡下;为什么从那里选择)最简单,那是因为我们肯定会为多个平台)。 因为目标(和生成的产品)必须具有唯一的名称,所以我不得不将其中一个作为主要(我选择了macOS),将另一个作为iOS(辅助)。 对于后者的名字,我刚刚附加了“ Touch”来区分它(这个想法来自您可能已经猜到的苹果公司Cocoa和Cocoa Touch框架的名字。) 分组源代码文件 下一个挑战是找到一种在项目中考虑或不考虑其指定目标的好方法,将源代码文件分组。 我最终选择使用简单分组,并为每组源代码文件生成一个文件夹。 (Xcode确实支持不带文件夹的项目内分组,某种程度上类似于Visual Studio解决方案文件夹,但至少在我开始使用的版本9中,此功能存在一个丑陋的错误-拖动非文件夹分组的项目有时会崩溃。 ) 最终,考虑到它包含的源代码的功能区域,以及一个组包含的代码对于我的项目目标(macOS和iOS)是公共的还是特定于一个的,我决定进行多级分组。 请注意,默认情况下,为每个目标Xcode创建了一个组(和一个文件夹),我还希望将该分隔保留为我的主层次结构分组。 但是,这再次要求一个目标(我选择了macOS)成为主文件夹,并同时包含特定的和通用的源代码文件,而另一个目标(iOS目标)获得了仅保留特定源代码文件的辅助文件夹。 如果您想将其复制粘贴到您的Xcode中,这是实际的源代码: 不过,我在使用示例应用程序时发现的一个重要方面是,我们不应该尝试通过将它们移动到项目结构下的公共文件夹(在那里成为子文件夹)来对应用程序进行分组,因为它似乎有些Xcode应用程序设置不要在此过程中进行更新,并且会在构建时生成特定的警告。 但是,最终我能做的是解决这个问题,即创建一个不带名为“ Samples”的文件夹的组,然后将所有示例应用程序文件夹拖到该文件夹​​中,并将它们全部放在项目结构中的单个可折叠树节点下。 (重要的是文件路径保持不变。) 部署产品 对于每个目标,Xcode都会生成一个框架文件,其中包含为该目标构建的二进制文件和一些元数据,消费者可以使用这些元数据来访问您的组件。 您可以在项目结构中为您生成的Products文件夹中看到框架文件,并且可以通过Finder的上下文菜单在Finder中打开每个文件的位置。 然后,您可以从Finder复制框架文件并将其托管在任意位置,例如可以从Web服务器下载的文件,也可以通过您管理的任何分发渠道发布该文件。 发布配置 您可能已经看到输出框架是使用Debug配置构建的,并且您可能希望在实际部署它们之前切换到Release。 要改为选择发布配置,只需从Xcode的顶部菜单中单击目标组合框,然后单击“编辑方案”。 然后,对于“运行”选择,将“构建配置”从“调试”更改为“发行”,关闭对话框,然后重新构建目标。 体系结构:iOS模拟器不是ARM! 但是你不流行。 您最终会注意到,即使您使用Release配置构建了iOS框架(以Touch后缀命名),也无法在所有架构上正常运行。 例如,如果您使用真实设备(或具有ARM体系结构的通用设备)构建框架,则输出框架将不适用于以模拟器为目标(使用x86体系结构)的iOS应用。 反之亦然。 因此,您还需要定义一个聚合目标,以便能够运行脚本以将为不同体系结构构建的框架“合并”为一个聚合的“胖”对象。 为此,请在新目标对话框的“跨平台”选项卡中创建一个类型为Aggregate的新目标,为其命名,如“ FramisTouch-aggregate”,并为其添加一个新的运行脚本阶段(使用“ +”按钮目标的“构建阶段”部分),并定义一些命令来执行所需的操作: 然后,可以通过构建聚合目标(很重要:之后)轻松地执行上述命令:通过从目标中选择通用iOS设备和模拟器,您已经在Xcode中构建了设备和模拟器框架(即针对两种类型的体系结构)组合框,然后重复构建输出。 您当然想知道这些命令实际上会做什么: 创建一个新目录(例如“ Release-iphoneaggregated”)作为目标(在项目的构建目录中); 将基于设备的框架的结构复制到新目录中; […]

模型视图控制器(MVC)

Model-View-Controller(MVC)设计是一个与应用程序的全局体系结构有关的高层,并根据对象在应用程序中扮演的一般角色对对象进行分类。面向对象的程序通过适应MVC可以从多种方面受益他们设计的设计模式。 这些程序中的许多对象倾向于更可重用,并且它们的接口倾向于更好地定义。 它主要包括三层: 1)模型层 2)查看图层 3)控制器层 1)模型层: 模型层包含以下组件: 网络代码 :此代码对于整个应用程序的网络通信非常有用 持久性代码:此代码用于实现核心数据,或仅通过将NSData blob直接保存到磁盘即可。 解析代码:解析网络响应之类的任何对象也应包括在模型层中。 模型对象封装了数据和基本行为,它们保存了应用程序的数据并定义了处理数据的逻辑。设计良好的MVC应用程序将其所有重要数据封装在模型对象中,任何数据都是应用程序持久状态的一部分一旦将数据加载到应用程序中,它应该驻留在模型对象中。 理想情况下,模型对象与用于呈现和编辑它的用户界面没有显式连接。 模型对象不应与界面和表示问题有关。 2)视图层: 当用户与您的应用进行交互时,他们正在与视图层进行交互。 视图不应该包含任何业务逻辑,因此被认为是应用程序的“哑巴”部分。 用代码术语,您通常会看到: UIView子类:这些类从基本的UIView到复杂的自定义UI控件。 UIViewController: UIViewController与自身的根UIView及其不同的周期(LoadView,ViewDidLoad)紧密耦合。 动画和UIViewController过渡。 UIKIT / APPKIT,Core Animation和Core Graphics的一部分的类 检查视图图层时,请使用以下内容作为检查清单: 它是否与模型层交互? 它是否包含任何业务逻辑? 它会尝试执行与UI不相关的任何操作吗? 如果我们很好地编写了这些类,则几乎可以随时重用它们。 视图对象向用户提供信息。视图对象知道如何显示并可能允许用户编辑应用程序模型中的数据。视图不应负责存储其显示的数据。视图对象可以位于负责仅显示模型对象的一部分,整个模型对象,甚至许多不同的模型对象。 视图有很多不同的种类。 视图对象倾向于可重用和可配置,并且它们在应用程序之间提供一致性。 在Cocoa中,AppKit框架定义了大量的视图对象,并在Interface Builder库中提供了许多视图对象。 通过重用AppKit的视图对象(例如NSButton对象),可以确保应用程序中的按钮的行为与其他任何Cocoa应用程序中的按钮一样,从而确保了应用程序之间外观和行为的高度一致性。 视图应确保其正确显示模型。 因此,通常需要了解模型的更改。 由于模型对象不应绑定到特定的视图对象,因此它们需要一种通用的方式来指示它们已更改。 3)控制器层: 控制器层是应用程序中最少可重用的部分,因为它涉及特定于域的规则。 控制器对象将模型绑定到视图。控制器对象充当应用程序的视图对象及其模型对象之间的中介。 控制器通常负责确保视图可以访问他们需要显示的模型对象,并充当视图了解模型更改的渠道。 控制器对象还可以为应用程序执行设置和协调任务,并管理其他对象的生命周期。 在典型的Cocoa MVC设计中,当用户通过视图对象输入值或指示选择时,该值或选择将传达给控制器对象。 控制器对象可能以某种特定于应用程序的方式解释用户输入,然后要么告诉模型对象如何处理此输入。 基于相同的用户输入,某些控制器对象还可能告诉视图对象更改其外观或行为的某个方面,例如告诉按钮禁用自身。 相反,当模型对象发生更改时(例如,访问新的数据源),模型对象通常会将更改传达给控制器对象,然后控制器对象请求一个或多个视图对象进行相应的更新。 MVC作为复合设计模式: Model-View-Controller是一种设计模式,由多个其他基本设计模式组成。这些基本模式共同定义了MVC应用程序的功能隔离和通信路径。与可可分配的基本模式不同的一组基本模式。 […]

调试UIViewAlertForUnsatisfiableConstraints

作为iOS平台上的应用程序开发人员,我经常遇到如下约束警告, 无法同时满足约束条件。 以下列表中至少有一个约束是您不想要的约束。 尝试以下操作: (1)查看每个约束,并尝试找出不期望的约束; (2)查找添加了一个或多个不必要约束的代码并进行修复。 ( “” “, ” “, ” “, ” <“,” “ ”, “ “, ” “ ) 将尝试通过以下方式恢复 打破约束 在UIViewAlertForUnsatisfiableConstraints上创建一个符号断点,以在调试器中捕获该断点。 当我看到此类问题时,我们立即使用UIViewAlertForUnsatisfiableConstraints设置了符号断点。 当我再次运行该应用程序以重现该问题时,Xcode将在上述约束警告处停止。 现在如何处理指针和汇编代码? 经过研究,我找到了一些调试此断点的解决方案。 如果您看到上面的图像,您会看到%rbp,%rsp,%rbx,%r15等字符串。这些属性保存视图和约束的地址,这是约束问题背后的原因。 我们可以在Xcode控制台中打印它们,以查看有关此内容的更多详细信息。 我通常从打印rbx开始,因为根据我的经验,它通常是NSArray ,其中包含该问题涉及的所有视图和约束。 打开Xcode控制台并执行以下命令。 po $ rbx 以上结果看起来与警告消息完全一样,因此,我们可以如何处理它。 三想记住这里, 程序执行在断点处停止 您具有约束问题所涉及的所有视图的内存地址。 LLDB使您可以在运行时评估obj-c表达式 如果查看po $ rbx命令的结果,可以看到view的内存地址。 例如UIView:0x7f94ff5b3c70 我通常会为某些视图提供外观并继续执行程序。 使用从上一个打印命令获得的内存地址,在Xcode控制台中执行以下命令。 ex [(UIView *)0x7f94ff5b3890 setBackgroundColor:[UIColor greenColor]] ex [(UIView […]