Photos 框架实践以及坑

Swift4.0--Photos框架的使用附从相簿中获取图片 首先发布Demo链接 Photos从相簿中获取图片效果展示 (一) Photos简介 在iOS 8之前,开发者只能用 AssetsLibrary 框架访问的用户的照片库。几年以来,相机应用和照片应用发生了显著的变化,增加了许多新特性,包括按时刻来组织照片的方式。但与此同时,AssetsLibrary 框架却没有跟上步伐。 随着 iOS 8 的到来,苹果给我们提供了一个现代化的框架 阅读详情

导读

对于 Photos 框架的介绍,推荐观看 objccn.io 的文章。写得真好,我写得的文章水准还差得老远啊。本文总结了近期使用 Photos 框架编写一个相册的经验,目前还有很大一部分的框架内容没有涉及到,后续会更新内容。

获取资源

照片库中有两种资源可供获取:PHAsset和PHCollection,前者代表图像或视频对象,后者是前者的集合或自身类型的集合。PHCollection是个基类,有PHAssetCollection和PHCollectionList两个子类,分别代表 Photos 里的相册和文件夹。以往使用 Photos 时,并没有注意到可以建立文件夹,似乎是从 Photos 框架才支持这个功能,而PHCollectionList里可嵌套PHAssetCollection和自身类型,还支持多重嵌套。获取PHAsset以及PHAssetCollection的过程类似于 Core Data,如下所示,只能通过类方法来返回PHFetchResult,遍历返回的结果来获取需要的资源。


PHAsset Fetch Method

PHAssetCollection Fetch Method


注意,PHAsset、PHAssetCollection和PHCollectionList 都是轻量级的不可变对象,使用这些类时并没有将其代表的图像或视频或是集合载入内存中,要使用其代表的图像或视频,需要通过PHImageManager类来请求。

请求图像(这里有巨坑)

关于PHImageManager类,NSHipster 有篇总结文章不错。

- requestImageForAsset:targetSize:contentMode:options:resultHandler:

你不应该生成该类的实例,而应该使用该类的提供的单例对象。该方法提供指定的尺寸的图像,与ALAssetsLibrary库相比,没有了方便的缩略图提供。不过要吐槽的是,ALAssetsLibrary库提供的缩略图往往尺寸太小并且质量很低,用在 TableView 上还可以。

需要注意的是,该方法在默认情况下是异步执行的,而且 Photos 库可能会多次执行 resultHandler 块,因为对于指定的尺寸,Photos 可能会先提供低质量的图像以供临时显示,随后会将指定尺寸的图像返回。如果指定尺寸的高质量的图像有缓存,那么直接提供高质量的图像。而这些行为,可以通过 options 参数来定制。

PHImageRequestOptions类用于定制请求。这里有巨坑。上面的方法返回指定尺寸的图像,如果你仅仅指定必要的参数而没有对 options 进行配置的话,返回的图像尺寸将会是原始图像的尺寸。或者,你指定的尺寸很小,这时候会按照你的要求来返回接近该尺寸的图像。在我的 iPad mini 一代上,对于自拍的图像,指定尺寸不超过(257, 257)的话,返回的图像尺寸和你预期的一样,其他情况下都是原始尺寸。PHImageRequestOptions有以下几个重要的属性:

synchronous:指定请求是否同步执行。
resizeMode:对请求的图像怎样缩放。有三种选择:None,不缩放;Fast,尽快地提供接近或稍微大于要求的尺寸;Exact,精准提供要求的尺寸。
deliveryMode:图像质量。有三种值:Opportunistic,在速度与质量中均衡;HighQualityFormat,不管花费多长时间,提供高质量图像;FastFormat,以最快速度提供好的质量。
             这个属性只有在 synchronous 为 true 时有效。
normalizedCropRect:用于对原始尺寸的图像进行裁剪,基于比例坐标。只在 resizeMode 为 Exact 时有效。

resizeMode 默认是 None,这也造成了返回图像尺寸与要求尺寸不符。这点需要注意。要返回一个指定尺寸的图像需要避免两层陷阱:一定要指定 options 参数,resizeMode 不能为 None。

除了必有的请求图像或是视频的功能外,PHImageManager添加了两大功能:
1.缓存图像,由其子类PHCachingImageManager实现,缓存效率和空间管理能满足大部分场景的需求;
2.裁剪图像,这个功能很久以前就有强烈的需求。六年前 StackOverflow 上 Cropping a UIImage 这个问题就被提出来了,方法也五花八门,然而这些方法可能会有各种小问题。官方的方法能让你避免这些小问题。使用方法可以参考 NSHipster 的总结文章里用人脸识别获取头像的例子。

localIdentifier vs URL

Photos 框架推出时,和原来的照片库 AssetsLibrary 框架之间还有些交互,PHAsset 类的+ fetchAssetsWithALAssetURLs:options:和PHAssetCollection类的 + fetchAssetCollectionsWithALAssetGroupURLs:options:可以利用原来的 AssetsLibrary 提供的 URL 进行转化,而在 iOS 9 中,原来的照片框架 AssetsLibrary 已经被废弃了,如今这两个方法也没有用处了。当初我还找过如何从 Photos 框架到 AssetsLibrary 框架的方法,理所当然地白费功夫,官方要淡化照片库中 URL 的概念,改之使用一个标志符来唯一代表一个资源。Photos 框架中的根类PHObject只有一个公开接口localIdentifier,AssetsLibrary 框架中无论是 Asset 还是 AssetGroup 的 URL 也是唯一标志符,而且同时还是动态变化的,每次启动应用后获取的 URL 和上一次是不一样的,而 AssetGroup 有一个 PersistentID 与PHObject的localIdentifier类似,但获取比较麻烦。
localIdentifier属性带来的最大好处是PHObject类实现了 NSCopying 协议,可以直接使用localIdentifier属性对PHObject及其子类对象进行对比是否同一个对象。

获取指定类型相册

这是最基本的一个用途,但是每次隔了几天就忘了具体的类型。
通过PHAssetCollection的以下方法来获取指定的相册:

func fetchAssetCollectionsWithType(_ type: PHAssetCollectionType, subtype subtype: PHAssetCollectionSubtype, options options: PHFetchOptions?) -> PHFetchResult

这个方法需要至少指定两个参数:

enum PHAssetCollectionType : Int {
    case Album //从 iTunes 同步来的相册,以及用户在 Photos 中自己建立的相册
    case SmartAlbum //经由相机得来的相册
    case Moment //Photos 为我们自动生成的时间分组的相册
}

enum PHAssetCollectionSubtype : Int {
    case AlbumRegular //用户在 Photos 中创建的相册,也就是我所谓的逻辑相册
    case AlbumSyncedEvent //使用 iTunes 从 Photos 照片库或者 iPhoto 照片库同步过来的事件。然而,在iTunes 12 以及iOS 9.0 beta4上,选用该类型没法获取同步的事件相册,而必须使用AlbumSyncedAlbum。
    case AlbumSyncedFaces //使用 iTunes 从 Photos 照片库或者 iPhoto 照片库同步的人物相册。
    case AlbumSyncedAlbum //做了 AlbumSyncedEvent 应该做的事
    case AlbumImported //从相机或是外部存储导入的相册,完全没有这方面的使用经验,没法验证。
    case AlbumMyPhotoStream //用户的 iCloud 照片流
    case AlbumCloudShared //用户使用 iCloud 共享的相册
    case SmartAlbumGeneric //文档解释为非特殊类型的相册,主要包括从 iPhoto 同步过来的相册。由于本人的 iPhoto 已被 Photos 替代,无法验证。不过,在我的 iPad mini 上是无法获取的,而下面类型的相册,尽管没有包含照片或视频,但能够获取到。
    case SmartAlbumPanoramas //相机拍摄的全景照片
    case SmartAlbumVideos //相机拍摄的视频
    case SmartAlbumFavorites //收藏文件夹
    case SmartAlbumTimelapses //延时视频文件夹,同时也会出现在视频文件夹中
    case SmartAlbumAllHidden //包含隐藏照片或视频的文件夹
    case SmartAlbumRecentlyAdded //相机近期拍摄的照片或视频
    case SmartAlbumBursts //连拍模式拍摄的照片,在 iPad mini 上按住快门不放就可以了,但是照片依然没有存放在这个文件夹下,而是在相机相册里。
    case SmartAlbumSlomoVideos //Slomo 是 slow motion 的缩写,高速摄影慢动作解析,在该模式下,iOS 设备以120帧拍摄。不过我的 iPad mini 不支持,没法验证。
    case SmartAlbumUserLibrary //这个命名最神奇了,就是相机相册,所有相机拍摄的照片或视频都会出现在该相册中,而且使用其他应用保存的照片也会出现在这里。
    case Any //包含所有类型
}

有些参数的命名十分令人困惑,我每次看了都晕菜。新的 Photos Kit 框架是在 iOS 8 中推出的,主类型分为三种类型:Album,SmartAlbum 以及 Moment。然而,对于前两者的分类我是比较困惑的。Mac 上支持智能文件夹,就是可以不管文件的物理位置而将一系列文件集合起来建立一个文件夹,可以说是物理相册和逻辑相册。而在 iOS 上,SmartAlbum 却给了相机衍生的相册,用户收集不同照片建立的逻辑相册被归类到 Album 类型的 AlbumRegular 下,十分反我的直觉。在文档中,SmartAlbum 是指内容会动态变化的相册,这样一来又有一个比较困惑的设计,PHAssetCollection 类有个属性 estimatedAssetCount,可以用来快速获取该相册中的照片和视频的数量,但是在 SmartAlbum 上该属性永远为0,动态相册没能实现对数量的监测。

注意,获取指定类型的相册时,主类型和子类型要匹配,不要串台。如果不匹配,系统会按照 Any 子类型来处理。对于 Moment 类型,子类型使用 Any。
1.获取用户自己建立的相册和文件夹(我称之为逻辑相册,非系统相册和从 iTunes 同步来的相册)有两种方法:

PHCollection.fetchTopLevelUserCollectionsWithOptions(nil) 
PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .AlbumRegular, options: nil)

在没有提供PHOptions的情况下,返回的PHFetchResult结果是按相册的建立时间排序的,最新的在前面。
2.获取相机相册:

PHAssetCollection.fetchAssetCollectionsWithType(.SmartAlbum, subtype: .SmartAlbumUserLibrary, options: nil)

另外:PHAsset的获取方式在 iOS 8.1 后发生了一些变化。以下的两个方法在 iOS 8.1后不再包含从 iTunes 同步以及在 iCloud 中的照片和视频。要获取 iOS 设备上本地的所有照片和资源只能从 PHAssetCollection 入手了。

 + fetchAssetsWithMediaType:options:
 + fetchAssetsWithOptions:

添加、删除、编辑

对照片库进行操作,可参见官方文档 Requesting Changes to the Photo Library,照片库中的资源都有对应的变更请求类:PHAssetChangeRequest, PHAssetCollectionChangeRequest和PHCollectionListChangeRequest, 而这些操作的请求都要求在PHPhotoLibrary的performChanges(_ changeBlock: dispatch_block_t!, completionHandler completionHandler: ((Bool, NSError!) -> Void)!)中的 changeBlock 中执行。注意,这里只是发出请求并没有做出实质的更改,因此想要根据更改结果更新 UI 的话不要在 completionHandler 中进行,而应该在 photoLibraryDidChange(changeInfo: PHChange!)中进行。三种变更请求中,删除和编辑操作都比较简单,而添加操作有需要注意的地方。

添加操作: placeholder 的用处

在相册中添加照片:

let createAssetRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(image)
let assetPlaceholder = createAssetRequest.placeholderForCreatedAsset
let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: album)
albumChangeRequest.addAssets([assetPlaceholder])

在文件夹中添加相册:

let fetchResult = PHCollection.fetchCollectionsInCollectionList(collectionList, options: nil)
let createSubAlbumRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(title!)
let albumPlaceholder = createSubAlbumRequest.placeholderForCreatedAssetCollection
let folderChangeRequest = PHCollectionListChangeRequest.init(forCollectionList: collectionList, childCollections: fetchResult)
folderChangeRequest?.addChildCollections([albumPlaceholder])

在文件夹中添加子文件夹:

let fetchResult = PHCollection.fetchCollectionsInCollectionList(collectionList, options: nil)
let createSubFolderRequest = PHCollectionListChangeRequest.creationRequestForCollectionListWithTitle(title!)
let subfolderPlaceholder = createSubFolderRequest.placeholderForCreatedCollectionList
let folderChangeRequest = PHCollectionListChangeRequest.init(forCollectionList: collectionList, childCollections: fetchResult)
folderChangeRequest?.addChildCollections([subfolderPlaceholder])

处理变更

对相册发出变更请求后,系统会通知用户是否允许,用户允许后才会发生实质上的变化,系统会发布通知。
首先,注册成为PHPhotoLibrary的观察者来接收变化通知:

PHPhotoLibrary.shareLibrary().registerChangeObserver(self)

然后,实现PHPhotoLibraryChangeObserver协议的photoLibraryDidChange(changeInfo: PHChange!)。官方有个很好的例子:Handling Changes: An Example,有以下几点需要注意:
1.在photoLibraryDidChange(changeInfo: PHChange!)的实现里将所有处理放在主线程里处理;
2.所有PHPhotoLibrary的观察者都会收到通知,不管观察者本身引用的内容是否发生变化,因此要根据观察者的情况来对通知进行过滤。从参数PHChange对象里能获得所有的变化,通过changeDetailsForObject:和changeDetailsForFetchResult:来获取细节。changeDetailsForObject:获取的细节只是PHObject子类对象本身的信息变化,包括是否有成员被删除以及是否有图像或视频发生变化两种信息,有用信息实在有限,要处理成员变化需要依靠后者;对一个PHFetchResult对象使用changeDetailsForFetchResult:获取的细节中只包含该PHFetchResult对象变化的信息,可以利用这点来对通知进行过滤处理。
3.通过changeDetailsForFetchResult:获取的PHFetchResultChangeDetails对象,包含了 FetchResult 的结果的所有变化情况以及 FetchResult 的成员变化前后的数据,需要注意的是成员变化的通知。
例如,通过

var rootCollectionsFetchResult = PHCollection.fetchTopLevelUserCollectionsWithOptions(nil)

获取所有用户建立的相册和文件夹,在photoLibraryDidChange(changeInfo: PHChange!)中通过以下方法获得PHFetchResultChangeDetails对象。

let fetchChangeDetails = changeInstance.changeDetailsForFetchResult(rootCollectionsFetchResult)

fetchChangeDetails.changedObject返回一组其内容或元数据发生变化的成员,返回的成员是更新后的成员对象。当用户对某个文件夹内的相册或子文件夹进行添加、删除和编辑操作即文件夹的内容而不是文件夹本身的属性发生变化时,通知中会该变化的信息吗?实际上只有在文件夹中添加相册或子文件夹时才会在fetchChangeDetails.changedObject中有所反应,而删除成员或是修改元数据等操作都不会在通知有所反应,你需要使用其他手段来跟踪变化。

iOS开发实战:利用AVFoundation与Photos框架实现视频转Live Photo 在移动应用开发中,多媒体处理是常见的核心需求,涉及视频编辑、图像处理和相册交互等技术。其基本原理是通过操作系统提供的原生框架(如iOS的AVFoundation)对媒体文件进行解码、处理和编码。这项技术的价值在于能够为应用增添丰富的动态内容展示能力,提升用户体验。在实际应用场景中,开发者常需实现视频格式转换、关键帧提取以及将处理结果无缝集成至系统相册等功能。本文聚焦于一个具体实践:如何利用AVFoundation框架进行视频裁剪与关键帧捕获,并结合Photos框架将生成的视频与图片配对,创建出iPhone系 阅读详情

相关推荐

从材料到磁场:ANSYS Workbench永磁体仿真全流程解析

本文详细解析了在ANSYS Workbench中进行永磁体仿真的完整流程。从钕铁硼等永磁材料的特性讲起,逐步指导如何在软件中搭建模型、定义关键磁化方向、设置边界条件与网格划分,并解读磁场分布结果。文章旨在帮助工程师掌握静磁场仿真核心技术,为电机、传感器等设备的设计与优化提供精准指导。

weixin_29229989的博客 272

关于自定义相册相关的PhotoKit小结

423141234132

victor的博客 462

别再纠结Dify了!实测对比RAGFlow和Dify,聊聊企业知识库到底该怎么选

本文深度对比了RAGFlow和Dify在企业知识库选型中的实际表现,从技术架构、性能指标、部署成本等多维度进行分析。RAGFlow在复杂文档处理和准确率方面表现突出,适合有专职技术团队的企业;而Dify则以低门槛和快速部署见长。文章提供了六维度评估法,帮助企业根据文档复杂度、准确率要求等技术指标做出明智选择。

weixin_30897233的博客 669

iOS-对图片操作---添加到自定义相册

转自:https://www.jianshu.com/p/7113c2c15e2c   图片操作---添加到自定义相册 实际上,自定义相册中的图片并不是实际的图片,而是对系统【相机胶卷】这个相册中的图片进行一个引用,所以将图片保存到自定义相册的第一步就是先保存到系统的【相机胶卷】中... 1.步骤 • 将图片保存到系统相册【相机胶卷】中 (1)C语言函数来保存 (2)AssetsLi...

iotjin的专栏 1523

eMMC FFU固件更新实战:从协议解析到设备修复

本文详细解析eMMC FFU固件更新技术,从协议原理到实战操作,涵盖EXT_CSD寄存器操作、命令流状态机解析及专业工具使用指南。通过真实维修案例,展示如何利用FFU机制修复设备故障,并提供高级优化技巧与安全注意事项,是硬件工程师和维修技术人员的实用参考。

weixin_29191761的博客 378

从智能家居到智慧城市:AI Agent Harness Engineering 作为统一控制中枢

我们可以把每个独立的智能系统看作一根带有独立功能的电线:智能家居Agent是负责家庭设备控制的电线,社区Agent是负责社区管理的电线,城市交通Agent是负责交通调度的电线,而AHE就是把这些分散的电线整合起来的「智能线束」:它不仅负责把不同接口、不同协议、不同层级的Agent连接起来,还提供统一的编排、调度、协同、观测能力,实现全局效用最大化的智能决策。

AI Agent Harness Engineering 202

关于iOS8之前和以后的相册图片获取实现

本期部分项目需求:获取相簿特定相册的图片,展示出来

shang1219178163的专栏 2588

西门子S7-1200模拟量的使用

模块类型核心参数输入信号处理输出信号配置转换原理数值范围TIA Portal配置编程要点 转换公式: 输出模拟量: 五、校准与线性化 硬件校准非线性补偿抗干扰措施数字滤波温度控制压力监控流量调节信号异常精度不足实践操作参考文档项目案例借鉴博客

weixin_51020122的博客 4769

iOS 自定义相册

目录(?)[-] One    将图片保存到系统的相册中Two    AssetsLibrary/AssetsLibrary.h>苹果原生框架Three  iOS8推出的Photos/Photos.h> 一共有两种方法自定义相册 第一种是iOS9之后过期的 AssetsLibrary/AssetsLibrary.h>苹果原生框架 第二种是iOS8推出的Photos/Photos.h> 苹果

六六的博客 1376

Hadoop与Kafka集群部署与优化实践指南

分布式系统是现代大数据处理的核心架构,其中Hadoop作为分布式存储与计算框架,Kafka作为分布式消息队列系统,共同构成了实时数据处理的基础设施。通过HDFS实现海量数据存储,结合YARN进行资源调度,而Kafka则保障了数据流的实时传输与高吞吐。这种技术组合在电商用户行为分析、物联网数据采集等场景中表现卓越。部署过程中需关注硬件资源配置、关键参数调优以及集群监控方案,例如通过调整HDFS块大小和Kafka partition数量来优化性能。合理运用Flume、Spark Streaming等工具可实现系

weixin_29061997的博客 360

tongweb中间件selectApp.jsp存在任意文件上传(含批量验证poc)

tongweb中间件selectApp.jsp存在任意文件上传(含批量验证poc)

weixin_43567873的博客 1983

Photos框架及坑(转自简书)

导读 对于 Photos 框架的介绍,推荐观看 objccn.io 的文章。写得真好,我写得的文章水准还差得老远啊。本文总结了近期使用 Photos 框架编写一个相册的经验,目前还有很大一部分的框架内容没有涉及到,后续会更新内容。 获取资源 照片库中有两种资源可供获取:PHAsset...

chuiteng1610的博客 441

【数据集】1980-2020年(5年)土地利用分类数据-中国科学院

简介1980-2020年每五年土地利用数据-中国科学院

WW、forever的博客 3932

photos框架的使用

参考资料 iOS开发-自定义专属相册 (详细干货) photo框架工具.zip 代码相关 使用 1> 导入框架头:#import <Photos/Photos.h> 2> 获取所有胶卷名字 #pragma mark 获取所有的胶卷的名字 + (NSMutableArray *)getAlbumObjects; #pragma mar...

公会驻地 327

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

从ALAssetsLibrary到Photos框架:JFImagePickerController 图片选择器迁移指南与XMP编辑图原理

**JFImagePickerController** 是一款经典的高性能 iOS 多选图片库(Pod 名:JFImagePicker),它基于老牌的 **ALAssetsLibrary**(AssetsLibrary 框架)实现相册多选、已选预览与超大图片内存优化。本文将带你理解它的架构与核心原理,给出一份从 ALAssetsLibrary 迁移到 **Photos 框架**的实操清单,并深入解

gitblog_01033的博客 351

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Pixelify Google Photos:非Pixel设备也能享受谷歌相册高级功能的3种方法

你是否曾羡慕Pixel手机用户能够享受谷歌相册的专属功能?现在,通过Pixelify Google Photos这个开源项目,任何Android设备都能解锁这些高级特性。这个基于MIT许可的LSPosed/EdXposed模块,通过巧妙的技术手段让Google Photos应用“误以为”你的设备是Pixel系列,从而开启一系列原本仅限Pixel用户的独家功能。 ## 🎯 为什么你需要Pixel

gitblog_01111的博客 849

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Google-Photos-Toolkit核心原理:揭秘浏览器端调用Google Photos API的实现

Google-Photos-Toolkit是一款强大的用户脚本工具,能够帮助用户在浏览器端实现对Google Photos库的筛选、搜索、组织和删除等操作。本文将深入剖析其核心原理,揭秘如何在浏览器环境下高效调用Google Photos API,为普通用户和新手开发者提供全面的技术洞察。 ## 工具简介:让Google Photos管理更简单 ✨ Google-Photos-Toolkit作

gitblog_00487的博客 267

Google Photos Deduper 使用教程

Google Photos Deduper 使用教程 项目介绍 Google Photos Deduper 是一个用于删除 Google Photos 中重复照片的本地运行 Web 应用和 Chrome 扩展。该项目由 mtalcott 开发,使用 React、Python、TypeScript 和 Docker 等技术构建。由于 API 使用限制、Google 应用验证过程的成本和用户隐私考虑,...

gitblog_00594的博客 981

Photos框架 - 自定义媒体资源选择器(数据部分)

我们从自定义个媒体选择器入手,来探讨一些Photos框架的用法,本篇博客我们主要介绍了使用Photos获取相册权限,读取媒体数据,以及如何配置读取的数据参数。下一篇博客我们将开始使用这些数据来构建一个媒体资源选择器的UI页面。

weixin_39339407的博客 1386

终极指南:如何在任何Android设备上解锁Google Photos的Pixel专属功能

想要在非Pixel手机上享受谷歌Pixel独有的Google Photos高级功能吗?Pixelify Google Photos就是你的完美解决方案!这个开源LSPosed模块能够"欺骗"Google Photos应用,让它以为你的设备是Pixel手机,从而解锁一系列高级功能。无论是免费的无限高质量照片存储,还是Pixel专属的AI编辑工具,现在都能在你的设备上体验。 ## 🤔 为什么你需要

gitblog_01020的博客 964
上一篇: Xcode打印乱起八糟的东西清除
下一篇: iOS 线程安全 记住这些方法
FFCoding
博客等级 码龄10年 2粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值