Tag: swift

在Swift 3中访问相机和照片库

我最近正在做一个项目,希望将图像存储在Firebase中。 我开始研究Firebase文档,尝试看看如何将图像上传到其“存储”功能,然后稍后在我的应用程序中将这些图像下拉。 但是,这样做的时候,我意识到我什至不知道如何允许用户拍摄新照片或从他们的照片库中选择一张照片! 我开始研究如何解决此问题,偶然发现了一个令人难以置信的资源: http://www.techotopia.com/index.php/An_Example_Swift_iOS_8_iPhone_Camera_Application。 我从那堂课中学到了很多,但是做了一些不同的事情。 该代码起初看起来很紧张,但是如果逐行将其分解,它就会变得更有意义。 就本博客而言,我仅创建了一个简单的单视图应用程序,该应用程序显示空白的imageView,允许用户从其相机或照片库添加图片,并使用所选图片更新imageView。 在进入代码之前,实际上有很多设置需要完成,所以我将逐步进行分解。 1.导入MobileCoreServices 很简单 MobileCoreServices带有Xcode中的默认库,因此您甚至无需使用CocoaPods或Carthage。 通过导入它,您可以访问我们稍后将使用的方法和属性。 2.采用正确的协议 我们需要采用的两个必要协议是UIImagePickerControllerDelegate和UINavigationControllerDelegate。 它们使我们能够访问一些必要的功能,这些功能将在显示相机/照片库以及确定图像后决定要执行的操作中使用。 3.更新Info.plist 对我而言,这是相对较新的东西。 在此之前,我唯一一次进入plist是允许我的应用程序对http地址(而不只是https)进行API调用(老实说,当时与我结对编程的那个人做了关于那)。 那么什么是plist? 好吧,如果您看到顶部,您将看到三个标题:“键”,“类型”和“值”。了解了我们对Swift的了解之后,我们可以假定这是一本字典。 为了我们的目的,我们希望请求访问用户的相机及其照片库。 为此,我们只需转到列表底部,将鼠标悬停在最后一项上,然后单击“ +”按钮即可。 这列出了可供选择的整个选项列表。 我们正在处理隐私问题,因此我们向下滚动到“隐私”部分并查找与相机有关的内容:“隐私-相机使用说明”。添加后,我们可以在“值”部分中添加一条消息。将会显示给用户,说明发生了什么。 在这种情况下,我们可以输入“此应用程序请求访问您的相机”之类的信息。这将在预先生成的警报控制器中显示此消息,例如: 我们可以执行类似的过程以允许访问照片库-“隐私-照片库使用说明”,并添加您想要的任何消息。 4.将Bool属性添加到您的ViewController 这个布尔的意义是什么? 好吧,它将告诉我们我们选择的图像是一张新照片(仅由我们的相机拍摄)还是不是(从我们的照片库中选择的一张照片)。 一旦我们实际选择要使用的图像,这将在以后派上用场。 5.创建UI并添加插座/操作 根据需要配置UI。 对于演示应用程序,我只添加了一个ImageView和一个Button。 然后,我们可以按常规方式将它们连接到我们的ViewController: 现在,我们将可以访问ImageView以及单击“添加图片”按钮时将发生的情况。 6.选择是拍摄新照片还是从照片库中选择 因此,我们已经执行了7的第6步,几乎没有编写任何代码! 就像我说的,涉及到很多设置。 让我们进入代码并分解这里发生的事情。 从根本上讲,我所要做的就是设置一个alertController(一旦您练习了,就很容易设置),它允许用户选择要使用相机还是图片库。 对于这两个动作,所有有意义的代码都发生在最后的闭包中(您在其中看到{(动作)在…}中)。 首先,我们检查所需的源是否可用。 在这种情况下,我们正在寻找相机,它是UIImagePickerControllerSourceType的枚举属性。 如果可用,我们声明一个名为“ imagePicker”的常量,并将其设置为等于默认的UIImagePickerController。 然后,我们将其委托设置为self(自己是我们的View Controller的实例),将它的sourceType设置为camera(在这种情况下也是我们要寻找的源),将其mediaType设置为kUTTypeImage,转换为String。 等等等等……那看起来很奇怪的“ kUTTypeImage”是什么? 从本质上讲,这意味着它是静止图像,实际上是默认的mediaType(因此我们实际上不需要这一行代码-很好地了解正在发生的事情)。 我们稍后将在代码中实际查看它,因此很高兴在这里首先看到它。 接下来,我们将allowEditing设置为false,因为在这种情况下,我们不希望用户能够编辑拍摄的图像。 然后,我们呈现imagePicker并将Bool属性设置为true,因为这是一张新图片。 […]

在连接的控制器中处理键盘事件

最近几个月,我们一直在开发Storgage应用程序(尚未在App Store上),并且我们希望分享开发该应用程序时使用的一种技术。 问题 我们应用程序的功能之一是使用内置的即时消息传递服务,以便用户彼此交谈并查看交易历史记录详细信息。 屏幕的设计如下所示: 如您所见,聊天区位于屏幕底部,当用户点击“键入消息”时,弹出系统键盘将其覆盖。 解 我们决定,当系统键盘弹出时,应显示一个动画的“键入消息”输入字段,并且应将聊天区域推到屏幕顶部。 退出键盘后(通过点击聊天区域或“发送”按钮),屏幕应返回其原始状态。 这是我们要实现的行为的示例: 问题二 在这一点上,我们面临另一个问题。 消息传递控制器是主屏幕控制器的子级。 家长必须将聊天窗口扩展到全屏状态,我们必须告诉它何时进行。 解决方案二 我们使用委托模式来通知父控制器键盘的出现和消失,以便可以正确地定位内置消息传递控制器。 实作 Storgage项目是用Objective-C编写的,但是为了更好地展示本文中的问题的解决方案,我们将创建一个用Swift编写的示例项目。 首先,让我们创建一个空的“ Single View Application”项目。 将其命名为“ ChildControllerKeyboard”,然后选择Swift作为语言。 然后添加两个类:从UIViewController继承的ContainerViewController和ChildViewController。 为此,请从菜单中选择文件>新建文件…。 然后从弹出窗口中选择“ Cocoa Touch Class”,并使用相应的值填充字段。 对ChildViewController重复上述步骤。 然后可以删除ViewController.swift文件。 现在切换到Main.storyboard并将控制器类从ViewController更改为ContainerViewController。 向主控制器的内容添加视图 将对象库中的视图对象放到控制器上,并设置以下约束,将其附加到屏幕边缘,并将高度设置为等于屏幕的一半: 尾随空格为:Superview = 0 前导空间:Superview = 0 最多空间:Superview = 0 等于以下高度:Superview = 0,Multiplier = 0.5 在“身份检查器”选项卡的“标签”字段中输入值“内容视图”,然后在“属性”检查器选项卡上将“背景”值更改为“浅灰色”。 最后,我们的控制器应如下所示: 添加子控制器 将来自对象库的“容器视图”对象放在控制器上“内容视图”下方,并设置以下约束,并将其附加到屏幕和“内容视图”的底部: 尾随空格为:Superview = […]

带有Swift属性,扩展名,枚举和泛型的备忘单。

在Swift中覆盖存储的属性: 快速存储的属性和计算的属性有两种属性 储存财产 存储的属性是与结构或类的实例相关联的变量。 Swift现在通过使用let和var分别表示常量和可变属性,使属性声明更加简洁 计算财产 除了存储的属性外,类,结构和枚举还可以定义计算的属性 ,而实际上并不存储值。 相反,它们提供了一个getter和一个可选的setter,以间接检索和设置其他属性和值。 现在的概念是我们不能覆盖存储的属性 它将引发错误,因为如果我们真的想覆盖存储的属性,则无法覆盖它,那么我们需要使其成为计算属性。 结论:如果要覆盖子类中的存储属性,则需要将其定义为计算属性。 进行一些扩展,有助于获得UIStoryboard对象以用于Application中存在的多个情节提要 通常,我们在一个项目中的不同模块中会使用多个情节提要,所以通常我们通过其名称来获取情节提要。 并且我们在此情节提要中实例化了适当的UIViewController,并针对项目中不同的不同情节提要反复进行此操作。 因此,更好的方法是创建UIStoryboard的扩展,并定义所有不同的Storyboard,然后在无需编写太多代码的情况下将其使用在任何您想使用的地方。 用法:就像我们要创建故事板主对象一样,我们只需编写以下行 它可以节省我们的时间,还可以避免错误输入(错误的故事板名称等) 创建用于实例化UIViewController的通用方法 通常,当我们从一个屏幕导航到另一个屏幕时,我们实例化一个UIViewController并将其推入导航控制器。 在这种情况下,我们需要编写类似的重复代码,而只需稍加修改即可。 因此,我将创建UIViewController的扩展,以减少我们的开发时间并保持我们的代码质量。 它还将减少重复的代码。 UIStoryboard和UIViewController扩展的组合用法 如果我们要实例化Main Storyboard中定义的UIViewController。 使用Main.storyboard中存在的标识符实例化UIViewController 2 。 如果要实例化xyz故事板中定义的UIViewController。 它将实例化OtherStoryBoard.storybard中定义的UIViewController。 重要说明 :-这里使用扩展UIViewController是其强制使用扩展UIStoryboard。 结论:正如我们看到的那样,扩展的巧妙使用将减少我们的工作量并保持代码质量。 我想提一个名字,没有他,这个博客是不可能的。特别感谢阿曼提供的宝贵意见。 面临的问题将邮件发送到Ved.bhumca11@gmail.com。

Swift中的内存问题

对于开发本机iOS应用程序的任何人来说,管理内存都是重要且必要的,如果您使用的是Apple的新编程语言Swift,则仍然如此。 我在最近的项目中遇到并解决了一些内存问题。 一点历史 内存是指在设备上存储信息所涉及的所有硬件。 您的iPhone有两种主要的数据存储方式:1.磁盘2.随机存取存储器(RAM)。 在iPhone上运行应用程序时,包含所有可执行指令的文件将被加载到RAM中。 同时,系统将占用一部分RAM,称为堆。 在该目录下,我们的类的所有实例都将在应用程序运行时运行。 当我们谈论内存管理时,我们指的是管理堆内存的过程。 这意味着管理堆上对象的生命周期,并确保在不再需要这些对象时将其释放,以便可以重用内存。 在Objective-C中,除了Int,CGRect等原语外,所有内容都是对象,因此将在堆上分配。 在Swift中,引用类型是在堆上分配的,而值类型不是。 管理堆内存非常重要,因为对象可能很大,而我们的应用程序只能从系统中获取这么多的内存。 内存不足会导致iOS应用运行缓慢,并最终导致应用崩溃。 尽管如今,由于我们的设备变得越来越强大,看到RAM过载变得越来越少了,但成为一个良好的内存公民总是很重要的。 Objective-C从未像Java这样的语言实现垃圾回收。 那时,我们需要进一步了解内存处理。 理解分配,复制,保留的含义以及如何平衡这些操作与相反的操作(如发布)至关重要。 基本规则是:无论何时创建对象,您都拥有它并负责释放它。 为什么泄漏可能很危险? 想象一下在init内创建通知时开始监听的对象。 它对此做出反应,将内容保存到数据库,播放视频或将事件发布到分析引擎。 由于需要平衡对象,因此我们在释放对象时在deinit内停止监听通知。 这不仅会增加应用程序的内存占用 ,而且还会带来不必要的副作用和崩溃。 如果这些物体泄漏会怎样? 它永远不会消亡,永远不会停止收听通知。 每次发布通知时,对象都会对此做出反应。 如果用户重复执行再次创建对象的操作,则将存在多个实例。 所有这些实例都响应通知并相互介入,在这种情况下, 崩溃将是最好的事情🙂 多个泄漏的对象对应用程序通知做出反应,更改了数据库,UI,破坏了应用程序的整个状态 在Swift中 ,当一个对象强烈引用另一个对象时,它会将其保存在内存中。 当我说对象时,基本上就是引用类型,类。 结构和枚举是值类型。 无法仅使用值类型创建保留周期。 在捕获和存储值类型(结构和枚举)时,没有诸如引用之类的东西。 尽管值可以保存对对象的引用,但值是复制而不是引用的。 当一个对象与第二个对象具有强关联时,它便拥有它。 第二个对象将保持活动状态,直到被释放。 这被称为S trong参考 。 只有将属性设置为nil时,第二个对象才会被销毁。 视图控制器泄漏 视图控制器或自定义视图在加载视图时可能立即开始泄漏。 之后,可能会发生一百万件事,但是通过此简单的测试,您可以确保viewDidLoad不会泄漏。 反初始化 一种方法是确保调用`deinit`。 当Deinit被调用时 指向对象的最后一个指针将被删除,并且内存 分配给它的将被清除。 使用打印或调试模式检查是否 从每个视图控制器中调用`deinit`; […]

在Swift中轻松进行结构初始化

您是否知道swift可为您的所有属性自动生成init ? 假设您有一个myStruct : struct myStruct { 让myString:字符串? 让myInt:Int? 让myDouble:加倍? } 在这种情况下,您甚至不需要编写init它已自动为您生成! 尝试实例化它,将看到如下所示的自动完成功能: 繁荣! 您节省了2分钟的打字时间! 但是有一个陷阱:您必须将所有这三个参数设置为一些值或nil myStruct(myString:“ Something”,myInt:nil,myDouble:nil) 它适用于课程吗? 没有

服务器端Swift与Kitura和Bluemix –编码自我–中

服务器端Swift与Kitura和Bluemix IBM Bluemix是一个云平台即服务解决方案,它使您能够专注于编写应用程序,而Bluemix处理大多数DevOps-y东西,例如网络,服务器,存储和软件依赖项。 它支持多种编程语言,包括Swift。 它也易于使用-您只需管理Web浏览器即可管理服务。 您甚至可以在IBM Swift Sandbox的浏览器中编写Swift代码。 本教程将带您了解Kitura和Bluemix入门的基础知识。 首先,我们将设置Bluemix,以便在准备就绪时可以以最小的努力上载我们的应用程序并启动服务器。 然后,我们将逐步完成Swift Package Manager和Kitura。 一旦建立了一定的熟悉度,我们将构建一些有用的东西并将其上传到Bluemix。 我们将使用Swift Package Manager中的SwiftCron软件包构建一个小型服务,该服务采用cron表达式并返回该表达式的可读描述。 设置IBM Bluemix 首先,请前往IBM BlueMix并注册免费的30天试用版。 登录时,系统会要求您命名组织的名称,这实际上是可以添加其他人员到您的团队并选择其位置的团队。 只需选择最接近您的位置-这些选项就限于Bluemix当前已设置基础架构的位置。 然后,将要求您设置一个空间,这是Bluemix组织应用程序和服务的方式。 然后,您将导航到仪表盘,该仪表盘是空的。 单击创建应用程序,我们将使事情变得更加生动。 Bluemix是基于Cloud Foundry构建的,Cloud Foundry是一种开源平台即服务(PaaS)。 然后,Bluemix为一些流行的Web框架(例如Python的Flask框架)提供了样板,以帮助您立即开始。 不幸的是,Swift还没有样板产品,因此我们将向下滚动这些诱人的选项,移至Cloud Foundry Apps部分。 为Swift选择运行时 。 设置您的应用名称。 我选择了SwiftCronServer,并将主机名保留为相同的自动填充值。 只需几分钟,我们已经在启动服务器。 那不是那么容易吗? 返回仪表盘,您应该可以看到您的新应用。 点击它。 然后,向下滚动到“持续交付”部分,然后单击“启用”。 您可以使用命令行界面手动将代码部署到Bluemix,但是将其向上游推送到Github并自动构建它更容易,更可靠。 在“持续交付工具链”页面上,向下滚动到可配置的集成。 链接您的GitHub帐户,然后单击“创建”。 轻松享受SPM和Kitura 现在是时候在本地运行Kitura项目了。 为您的项目创建一个新文件夹。 mkdir SwiftCronServer cd SwiftCronServer 我们将要使用的Kitura和Cron库都可以通过Swift Package Manager作为软件包使用,因此,我们将使用带有swift […]

聪明地使用Swift扩展

对Swift来说是新手的开发人员,对于他们来说,扩展可能是一个新名词,所以我想与Swift扩展及其使用分享我的经验。 什么是扩展名? 扩展为现有的类,结构,枚举或协议类型添加了新功能。 -Apple Swift开发人员参考 快速扩展使您可以将行为添加到任何Type以及现有Type中 。 让我告诉你它是如何工作的。 快速扩展还有其他用途,可以提高代码的可读性。 它还可以帮助您使代码井井有条。 协议一致性 当我们需要确认一个或多个协议时,可以将其实现为该类的扩展。 这就是我们可以确认协议的方式。 我们可以将协议的所有功能放到扩展模块中。 会的。 我通常使用pragma标记来执行此操作,因为这样做是为了提高代码的可读性。 实用标记在跳转栏中添加视觉标记,有助于在文件内快速导航。 我们可以使用UITableViewDelegate , UITableDataSource , UIWebDelegates等预定义协议进行此操作 。我们可以分隔每个协议 带有单独的实用标记的确认,以便我们可以轻松地在文件中导航。 代码分离 这是将整个代码分成多个命名串的另一种方法。 我们仅收集具有共同或联合任务的行为组。 见图。 保留初始化程序 当我在需要在我的一个项目中保留结构的初始化程序时学会了这一技巧。 当我做到这一点时,我就像哇……扩展使我的生活变得很认真,很高兴与大家分享这一点。 让我举一个例子,这对您来说更有意义。 在上面的示例中,有一个名为Address的结构,其属性为houseNumber,city和state。 Swift提供了一个免费的初始化器,可用于实例化Address结构的对象。 对于Struct,我们有一个免费的初始化程序,用于初始化其所有属性(请参见上图中的蓝色部分) 如果我们需要自定义初始化程序怎么办? 在某些情况下可能需要自定义初始化程序。 因此,我们通常要做的是看一下。 我们添加了自定义初始化程序,就像我在上图中添加的一样。 现在我要讲的重点是不要失去您的注意力。 当我们添加这样的自定义初始化程序时,我们只是丢失了默认的初始化程序。 现在,我们只有定制的初始化程序来实例化Address结构的实例。 那么我们如何克服这个缺点呢? 是的,您是对的,Swift扩展可以解决此缺点。 当我们添加自定义初始化程序作为扩展时,会发生什么? 让我们看看 瞧,现在我们有了两个初始化器。 华友世纪🙂 摘要 Swift扩展使您可以向任何类,结构或枚举添加行为,即使您无权访问原始源代码(就像我们对UIColor所做的那样)。 还使我们能够以井井有条的方式来编写智能代码,使代码更整洁,更易读。 现在轮到您了,去玩扩展程序。 所以,伙计们,我已经分享了我在Swift扩展方面的经验,我仍在学习和探索更多的智能编码方法。 让我知道您的想法,欢迎提出建议。

Swift —核心数据

花了点时间来研究一下Core Data的使用,以下是一些摘录,后面有附参考喔! 什么是核心数据? 核心数据不是数据库 ,您不应该期望它像数据库一样。 广义上讲,核心数据是应用程序的模型层。 贯穿iOS SDK的是Model-View-Controller模式中的Model 。 核心数据既不是应用程序的数据库,也不是将数据持久保存到数据库的API。 核心数据是管理对象图的框架 。 就这么简单。 核心数据可以通过将对象图写入磁盘来保留该对象图,但这不是框架的主要目标。 核心数据栈 核心数据堆栈是核心数据的核心。 堆栈的关键对象是托管对象模型 , 持久性存储协调器以及一个或多个托管对象上下文 。 NSManagedObjectModel 托管对象模型表示应用程序的数据模型。 即使Core Data不是数据库,您也可以将托管对象模型与数据库的模式进行比较 ,也就是说,它包含有关对象图的模型或实体,它们具有哪些属性以及它们如何关联的信息。另一个。 NSPersistantStore协调员 顾名思义, NSPersistentStoreCoordinator对象将数据持久保存到磁盘,并确保持久存储和数据模型兼容。 它在持久性存储和托管对象上下文之间进行中介,还负责加载和缓存数据。 那就对了。 核心数据已内置缓存。 持久存储协调员是核心数据乐队的指挥。 尽管它在核心数据堆栈中起着重要作用,但您很少会直接与其交互。 NSManagedObjectContext NSManagedObjectContext对象管理模型对象 ( NSManagedObject类的实例)的集合 。 一个应用程序可能具有多个托管对象上下文。 每个托管对象上下文均由持久性存储协调器支持。 您可以将托管对象上下文视为在其上使用模型对象的工作台。 您加载它们,对其进行操作,然后将其保存在该工作台上。 加载和保存由持久性存储协调器协调。 您可以有多个工作台,例如,如果您的应用程序是多线程的,这很有用。 以上是Core Data的核心要素,ref。是多个的完整教学文章,推荐继续往下读喔! 参考 核心数据和Swift:核心数据栈 自己实作的核心数据(创建,读取,更新和删除记录)的应用范例:https://github.com/piggogo0629/FoodPin ==============后续的参考。 学习:一些重点概念================ 提取记录的核心数据故障 :这是为了核心数据专门的设计,只有真正使用到的时候才会把真实数据加载到内存。 核心数据试图将其内存占用量保持在尽可能低的水平,而实现该目标所使用的策略之一就是错误 。 […]

iOS也很有趣,您想尝试一下吗? 来加入我们

我们一直在寻找热情,才华的人才加入我们的团队! 这次我们正在寻找iOS开发人员。 也许是你! 检查:https://railwaymen.org/careers/ios_… 要求: Swift和/或Objective-C的知识 Xcode / iOS SDK知识 移动开发技能 团队合作能力 具有足够的英语知识,可以阅读文档 对自我发展的渴望 专注于任务完成 现在关于我们的几句话: 我们是由三个拥有2009年以上Web开发经验的朋友于2009年成立的。 当他们第一次遇到Ruby on Rails技术时,这是一见钟情。 越来越多的项目促使他们与其他人分享他们的宝贵经验,并创建了一个团队来帮助企业家将出色的想法转变为Web和移动解决方案。 我们到了! 我们的目标是以具有竞争力的价格为每个客户提供最优质的网络和移动服务。 我们注重个人需求,并且能够在关注细节的前提下提供专业的解决方案。 作为软件公司,我们拥有所有适当的工具,可将您的想法转变为Web和移动应用程序。 我们专注于Ruby on Rails,Android和iOS。 我们很棒,因为有很棒的人! try我们努力营造一种友情和家庭氛围,同时保持对我们工艺的专业奉献。 为什么在铁道部工作? 我们公司如何激励员工? 首先的气氛! 但不仅🙂 您可以在8:00至10:00之间开始工作 每天您都可以品尝美味的咖啡和多种茶 每周一次,我们提供一定量的维生素=新鲜水果 每周一次,您可以订购自己喜欢的披萨 能源短缺? 您可以订阅OK System并升级锻炼 您可以享受迷你台球桌,桌上足球,棋盘游戏或借用我们的其中一本书。 您可以在这里申请:https://railwaymen.org/careers/ios_…

Swift,Xcode 8.1,NSTableView,绑定和数组控制器

从iOS开发转向macOS开发时,您理所当然的一件事就是iOS中的表格清晰明了。 UITableViews真正构成了许多iOS体验的骨干-明确定义了与它们的交互,并且对其进行了很好的记录和教导。 macOS和NSTableViews并非如此! 最初,我的印象是,就像在iOS上一样,将只有一种“正确”的方式来制作表格。 但是,在代码内实现和绑定之间,我感到困惑和迷茫。 这篇文章将通过使用绑定对NSTableView进行非常基本的设置。 有很多注释和屏幕截图,特别是因为要管理的屏幕太多….好吧,让我们深入研究! 第1步:准备数据模型 这里没有超级幻想。 让我们从PONSO开始。 类SomeDoctor:NSObject { var variable1:Int = 0 var variable2:Int = 0 var variable3:Int = 0 } 在上面,我们要做的就是创建一个NSObject并实例化一些变量。 请注意这些变量名,因为稍后我们将直接绑定它们(按名称)! 第2步:设置您的NSViewController 再次,这里没有幻想。 让我们创建典型的NSViewController,但是这次要注意创建一个动态类型的数组,如下所示: 类SimultaneousSummaryViewController:NSViewController { … @IBOutlet var arrayController:NSArrayController! 动态var临床医生= [SomeDoctor]() … } “动态”在这里只是意味着编译器将退出并寻找合适的Objective-C编译器来实现。 您可以在此处阅读有关该想法的更多信息。 当我们在这里时,我们还创建了一个NSArrayController引用-这是可选的! 我们严格不需要任何东西,但是制作完成后,您可能会感到不舒服。 步骤3:建立您的NSArrayController 找到您的NSArrayController对象,然后将其拖放到情节提要或xib文件中的NSViewController中。 步骤4:绑定,绑定,绑定! 突出显示您刚刚创建的NSArraryController。 展开右侧面板,然后选择“绑定”选项卡 展开后,请尝试使以下参数与您所拥有的匹配。 在上面,我们所做的是将NSArrayController绑定到NSViewController(明确地)。 现在,我们还将其绑定到我们先前定义的变量,并使该变量可用。 步骤5:绑定您的NSTableView 我们到家了! 将NSTableView拖放到情节提要/ […]