在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,因为这是一张新图片。

除了sourceType是“ photoLibrary”之外,我们可以为cameraRollAction重复基本上相同的过程。

如果您多花一点钱,您会发现实际上还有一个名为“ savedPhotosAlbum”的选项。有什么区别? 从我广泛的研究中可以很好地发现(我将它们切换为代码,并使用“ photoLibrary”和“ savedPhotosAlbum”的不同组合运行了该项目),. isSourceTypeAvailable方法可以很好地使用。 但是,如果将imagePicker.sourceType设置为photoLibrary,则会在照片库中获得所有相册,而如果将其设置为savedPhotosAlbum,则会直接进入“ Moments”文件夹。 可能有一种方法可以更改您在自己的电话设置中进入的文件夹,但是对于本博客而言,只知道photoLibrary将您带到整个库,而savePhotosAlbum仅将您带到一个相册。 另一个区别是我们的Bool属性设置为false,因为这不是新图像。

之后,我们只需将我们的两个动作添加到警报中并显示:

如果运行该应用程序,则应该看到显示了alertController,并且能够访问相机和照片库:

7.实现选择图像时发生的情况

为了正确完成此应用程序,我们需要设置两个委托方法(不是必需的,但您确实应该这样做):didFinishPickingMediaWithInfo和imagePickerControllerDidCancel。 您可能会从名称中猜出,第一个决定当拾取图像时发生的事情,第二个决定当用户决定不拾取图像并按下“取消”时发生的事情。一个:

首先要注意的是,在函数参数中,有一个称为“ info”的信息,我们可以看到它是一个字典。 如果我们对文档进行更深入的研究,将会发现此字典的键是不同的类型(UIImagePickerControllerMediaType,UIImagePickerControllerOriginalImage,UIImagePickerControllerEditedImage等)。 您可以打赌,我们希望访问这些键上的某些值。 因此,首先,我们声明一个名为“ mediaType”的常量,并将其设置为等于键“ UIImagePickerControllerMediaType”上的值,并将其强制转换为NSString。 如果该mediaType等于String形式的kUTTypeImage(我们知道这是因为这是我们设置imagePicker时将mediaType设置为的内容),那么我们将执行以下操作:

  1. 声明一个名为“ image”的新常量,该常量访问“ UIImagePickerControllerOriginalImage”处的值(因为我们没有编辑该图像)并将其强制转换为UIImage
  2. 将此图像设置为等于我们ViewController上的imageView的图像
  3. 如果是新图像(来自相机),则使用“ UIImageWriteToSavedPhotosAlbum”方法将其存储在保存的照片中。 (您会注意到,在此方法中,我们调用了另一个名为“ imageError”的函数。请记住这一点,因为稍后将对其进行解释!

然后,我们可以关闭视图,并返回到正常的ViewController,我们将注意到它已经用我们选择的图像进行了更新。

然后,我们需要实现第二个功能:

哇。 简单得多。 基本上,如果用户按下“取消”,则只需关闭视图。

上面我提到了保存图像时调用的另一个函数。 这很有用,因为如果由于某种原因无法保存图像,用户应该知道。 让我们看一下:

这甚至来自哪里? 好吧,如果您命令并单击进入UIImagePickerControllerDelegate,您将在底部看到他们已将其写为注释。 他们告诉您如何设置方法签名(出于可读性考虑,我将其称为“ imageError”而不是“ image”)。 它看起来很多,但是再次,它只是一个警告控制器,如果有错误(错误!= nil),它将显示出来。 它只是告诉用户无法保存图像。

在那里,您就可以使用它-一个允许用户访问相机和照片库以选择图像并使用该图像更新imageView的应用程序。 我承认代码是密集的,但是随着重复和专注于每一行的工作,它变得更容易理解。