Swift - 监听照片库里的变化(自动获取最新添加的图片)

当我们使用微信时会发现它有个预判“ 你可能要发送的照片”的功能,具体操作步骤如下:
  • 先打开微信进行聊天,然后将微信退到后台。
  • 接着进行一些拍照或者截图操作。
  • 再回到微信中,点击输入框旁边的加号发送附件。微信便会自动提示是否需要发送刚刚新增的那张照片,并显示照片的缩略图。(如果刚才新增了多张,则显示最后添加的那张。)
原文:Swift - 监听照片库里的变化(自动获取最新添加的图片)

1,实现原理

  • 要实现这个功能其实很简单 ,就是程序启动后监听照片库中资源的变化。
  • 一旦有变化便会触发 PHPhotoLibraryChangeObserver 代理的 photoLibraryDidChange 方法。
  • 我们在 photoLibraryDidChange 方法中可以判断具体的变化类型,比如时新增、修改还是删除,然后提示给用户。


2,效果图

(1)程序启动的时候获取当前所有照片资源,并添加监听。这时界面上什么都不显示。
原文:Swift - 监听照片库里的变化(自动获取最新添加的图片)

(2)双击  home 键退回桌面,进入到相册中。我们删除  1 张照片,修改  1 张照片,新增两张照片(一张截屏图片、一张拍照图片)
原文:Swift - 监听照片库里的变化(自动获取最新添加的图片)

(3)再次回到刚才的应用,会发现控制台打印出刚才照片库中的所有变化。同时界面上显示出最新添加的那张照片的缩略图。
原文:Swift - 监听照片库里的变化(自动获取最新添加的图片) 原文:Swift - 监听照片库里的变化(自动获取最新添加的图片)

3,样例代码

(1) Info.plist  配置
由于苹果安全策略更新,在使用  Xcode8  开发时,需要在  Info.plist  配置请求照片相的关描述字段( Privacy - Photo Library Usage Description
原文:Swift - 监听照片库里的变化(自动获取最新添加的图片)

(2) ViewController.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import  UIKit
import  Photos
 
class  ViewController UIViewController  {
     
     //取得的资源结果,用来存放的PHAsset
     var  assetsFetchResults: PHFetchResult < PHAsset >!
     
     //带缓存的图片管理对象
     var  imageManager: PHCachingImageManager !
     
     //用于显示缩略图
     var  imageView:  UIImageView !
     
     //缩略图大小
     var  assetGridThumbnailSize: CGSize !
     
     override  func  viewDidLoad() {
         //imageView初始化
         imageView =  UIImageView ()
         imageView.frame =  CGRect (x:20, y:40, width:100, height:100)
         imageView.contentMode = .scaleAspectFill
         imageView.clipsToBounds =  true
         self .view.addSubview(imageView)
         
         //初始化和重置缓存
         self .imageManager =  PHCachingImageManager ()
         
         //计算我们需要的缩略图大小
         let  scale =  UIScreen .main.scale
         assetGridThumbnailSize =  CGSize (width: imageView.frame.width*scale ,
                                         height: imageView.frame.height*scale)
         
         //申请权限
         PHPhotoLibrary .requestAuthorization({ (status)  in
             if  status != .authorized {
                 return
             }
             
             //启动后先获取目前所有照片资源
             let  allPhotosOptions =  PHFetchOptions ()
             allPhotosOptions.sortDescriptors = [ NSSortDescriptor (key:  "creationDate" ,
                                                                  ascending:  false )]
             allPhotosOptions.predicate =  NSPredicate (format:  "mediaType = %d" ,
                                                      PHAssetMediaType .image.rawValue)
             self .assetsFetchResults =  PHAsset .fetchAssets(with: .image,
                                                           options: allPhotosOptions)
             print ( "--- 资源获取完毕 ---" )
             
             //监听资源改变
             PHPhotoLibrary .shared().register( self )
         })
     }
     
     override  func  didReceiveMemoryWarning() {
         super .didReceiveMemoryWarning()
     }
}
 
//PHPhotoLibraryChangeObserver代理实现,图片新增、删除、修改开始后会触发
extension  ViewController : PHPhotoLibraryChangeObserver {
     
     //当照片库发生变化的时候会触发
     func  photoLibraryDidChange(_ changeInstance:  PHChange ) {
         //获取assetsFetchResults的所有变化情况,以及assetsFetchResults的成员变化前后的数据
         guard  let  collectionChanges = changeInstance.changeDetails( for :
             self .assetsFetchResults  as PHFetchResult < PHObject >)  else  return  }
         
         DispatchQueue .main.async {
             //获取最新的完整数据
             if  let  allResult = collectionChanges.fetchResultAfterChanges
                 as PHFetchResult < PHAsset >{
                 self .assetsFetchResults = allResult
             }
             
             if  !collectionChanges.hasIncrementalChanges || collectionChanges.hasMoves{
                 return
             } else {
                 print ( "--- 监听到变化 ---" )
                 //照片删除情况
                 if  let  removedIndexes = collectionChanges.removedIndexes,
                     removedIndexes.count > 0{
                     print ( "删除了\(removedIndexes.count)张照片" )
                 }
                 //照片修改情况
                 if  let  changedIndexes = collectionChanges.changedIndexes,
                     changedIndexes.count > 0{
                     print ( "修改了\(changedIndexes.count)张照片" )
                 }
                 //照片新增情况
                 if  let  insertedIndexes = collectionChanges.insertedIndexes,
                     insertedIndexes.count > 0{
                     print ( "新增了\(insertedIndexes.count)张照片" )
                     print ( "将最新一张照片的缩略图显示在界面上。" )
                     
                     //获取最后添加的图片资源
                     let  asset =  self .assetsFetchResults[insertedIndexes.first!]
                     //获取缩略图
                     self .imageManager.requestImage( for : asset,
                                             targetSize:  self .assetGridThumbnailSize,
                                             contentMode: .aspectFill, options:  nil ) {
                                                 (image, nfo)  in
                                                 self .imageView.image = image
                     }
                 }
             }
         }
     }
}

原文出自: www.hangge.com   转载请保留原文链接: http://www.hangge.com/blog/cache/detail_1515.html
SwiftUI中有多种方式可以监听值的变化。最常用的方法是使用`@State`、`@Binding`和`@ObservedObject`属性包装器。 首先,对于简单的值类型,可以使用`@State`属性包装器来监听变化。通过将属性标记为`@State`,使其成为视图的一部分,并且当该属性的值发生变化时,视图将自动重新渲染。例如,下面的代码演示了如何监听一个字符串的变化: ```swift @State private var name = "SwiftUI" var body: some View { VStack { Text("Hello, \(name)!") TextField("Enter your name", text: $name) } } ``` 当用户在文本字段中输入时,`name`属性将随之更新,并且视图将实时更新以反映新的值。 其次,对于需要在不同视图之间共享属性的情况,可以使用`@Binding`属性包装器。通过将该属性标记为`@Binding`,可以在不同的视图之间创建一个双向链接,使它们共享相同的值。当该值在一个视图中改变时,其他视图也会自动更新。以下是一个使用`@Binding`的示例: ```swift struct ContentView: View { @State private var isOn = false var body: some View { VStack { Toggle("Toggle", isOn: $isOn) AnotherView(isOn: $isOn) } } } struct AnotherView: View { @Binding var isOn: Bool var body: some View { Text(isOn ? "ON" : "OFF") } } ``` 在这个例子中,当用户在开关上切换时,`isOn`属性将更新,并且`AnotherView`中的文本将相应地改变。 最后,当需要监听自定义类(如ObservableObject的子类)中的属性变化时,可以使用`@ObservedObject`属性包装器。该属性包装器用于在视图中引用一个可观察对象,并且当该对象的某个属性发生变化时,视图将自动重新渲染。以下是一个使用`@ObservedObject`的示例: ```swift class DataStore: ObservableObject { @Published var counter = 0 } struct ContentView: View { @ObservedObject var dataStore = DataStore() var body: some View { VStack { Text("Counter: \(dataStore.counter)") Button("Increment") { dataStore.counter += 1 } } } } ``` 在这个例子中,`DataStore`是一个可观察对象,其中的`counter`属性通过`@Published`属性包装器进行了标记。当用户点击按钮时,`counter`属性将增加,并且视图将自动重新渲染以反映新的值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值