热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

聊聊ALAssetsLibrary与Photos

ALAssetsLibrary和Photos都是Apple提供访问系统相册资源的两个标准库,前者在iOS9之后已经被弃用,后者在iOS8上开始支持。可想

ALAssetsLibraryPhotos都是Apple提供访问系统相册资源的两个标准库,前者在iOS9之后已经被弃用,后者在iOS8上开始支持。可想而知,Photos库提供了更全面更友好的接口。

本文通过对比两者的用法来系统地学习一下“iOS访问系统相册资源”的知识点。重点会放在新的Photos库。

首先来看看旧的ALAssetsLibrary库。

ALAssetsLibrary

An instance of ALAssetsLibrary provides access to the videos and photos that are under the control of the Photos application.

ALAssetsLibrary相对来说是简洁一些的,只有5个类:

  • ALAsset 表示一个照片/视频资源实体
  • ALAssetRepresentation 表示一个资源的详细信息
  • ALAssetsFilter 设置拉取条件(图片?视频?全部?)
  • ALAssetsGroup 表示一个相册(照片组)
  • ALAssetsLibrary 对相册的实际操作接口

创建一个ALAssetsLibrary:

ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];

这里要注意:“AssetsLibrary 实例需要强引用” ,引用官方文档:

The lifetimes of objects you get back from a library instance are tied to the lifetime of the library instance.

可以如下测试:

- (void)viewDidLoad {
    [super viewDidLoad];
    _photos = [NSMutableArray new];

    ALAssetsLibrary *al = [[ALAssetsLibrary alloc] init];
    [al enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
        if (group) {
            [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
                if (result) {
                    [_photos addObject:result];
                }
            }];
            *stop = YES;
        }
    } failureBlock:^(NSError *error) {

    }];
    //由于ALAssetsLibrary的所有操作都是异步的,这里要在主线程
    //延迟访问_photos
   dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self processResAssets];
    });
}

- (void)processResAssets {
    for (ALAsset *asset  in _photos) {
        CGImageRef *imgRef = asset.thumbnail;
        UIImage *img = [UIImage imageWithCGImage:imgRef];
        NSLog(@"%@",img);
    }
}

上面代码中的ALAssetsLibrary实例是局部变量,在processResAssets方法中访问_photos时,由于_photos存储的只是代表资源文件的指针信息,真正保存资源文件的AssetsLibrary已经被释放了,所以取出来的资源都是nil的。

所以我们要确保ALAssetsLibrary实例是strong类型的属性或者是单例的

ALAssetsLibrary类定义了一些Block,其中

typedef void (^ALAssetsLibraryGroupsEnumerationResultsBlock)(ALAssetsGroup *group, BOOL *stop)

可以设置stop为true来终止block, 而不能像普通的block一样通过return来终止,其他类似的block都是这个用法。

ALAssetLibrary还有一个要注意的写入优先原则,就是说在利用 AssetsLibrary 读取资源的过程中,有任何其它的进程(不一定是同一个 App)在保存资源时,就会收到 ALAssetsLibraryChangedNotification,让用户自行中断读取操作。最常见的就是读取 fullResolutionImage 时,有进程在写入,由于读取 fullResolutionImage 耗时较长,很容易就会 exception。

ALAssetsLibrary提供的接口主要是两大类:

- (void)writeImageToSavedPhotosAlbum:(CGImageRef)imageRef orientation:(ALAssetOrientation)orientation completionBlock:(ALAssetsLibraryWriteImageCompletionBlock)completionBlock
- (void)writeImageToSavedPhotosAlbum:(CGImageRef)imageRef metadata:(NSDictionary *)metadata completionBlock:(ALAssetsLibraryWriteImageCompletionBlock)completionBlock
- (void)writeImageDataToSavedPhotosAlbum:(NSData *)imageData metadata:(NSDictionary *)metadata completionBlock:(ALAssetsLibraryWriteImageCompletionBlock)completionBlock
- (void)writeVideoAtPathToSavedPhotosAlbum:(NSURL *)videoPathURL completionBlock:(ALAssetsLibraryWriteVideoCompletionBlock)completionBlock

- (void)enumerateGroupsWithTypes:(ALAssetsGroupType)types usingBlock:(ALAssetsLibraryGroupsEnumerationResultsBlock)enumerationBlock failureBlock:(ALAssetsLibraryAccessFailureBlock)failureBlock
- (void)assetForURL:(NSURL *)assetURL resultBlock:(ALAssetsLibraryAssetForURLResultBlock)resultBlock failureBlock:(ALAssetsLibraryAccessFailureBlock)failureBlock 
- (void)groupForURL:(NSURL *)groupURL resultBlock:(ALAssetsLibraryGroupResultBlock)resultBlock failureBlock:(ALAssetsLibraryAccessFailureBlock)failureBlock

可以看到,ALAssetsLibrary并没有提供的接口。

ALAssetsLibrary在第一次增、查的时候会提示用户打开访问相册的权限,这帮开发者省略了自己写权限判断的逻辑。当然,前提是在项目的info.plist中定义了Privacy - Photo Library Usage Description这个key,否则会crash。

ALAsset定义了很多资源的属性,比如ALAssetPropertyLocationALAssetPropertyDurationALAssetPropertyOrientation等等,可以通过- (id)valueForProperty:(NSString *)property方法来获取值。

可以通过thumbnailaspectRatioThumbnail属性获取资源的缩略图。

虽然ALAssetsLibrary没有直接提供更新资源的接口,但是ALAsset自己提供了。ALAsset不仅可以更新资源数据,还可以选择直接覆盖当前资源还是生成一个新的资源。更新的前提是editable属性为true。

//把当前ALAsset更新之后的数据写到新的ALAsset对象中去
- (void)writeModifiedImageDataToSavedPhotosAlbum:(NSData *)imageData metadata:(NSDictionary *)metadata completionBlock:(ALAssetsLibraryWriteImageCompletionBlock)completionBlock 
- (void)writeModifiedVideoAtPathToSavedPhotosAlbum:(NSURL *)videoPathURL completionBlock:(ALAssetsLibraryWriteVideoCompletionBlock)completionBlock
//直接将更新后的资源数据覆盖原来的资源上,AssetURL不变
- (void)setImageData:(NSData *)imageData metadata:(NSDictionary *)metadata completionBlock:(ALAssetsLibraryWriteImageCompletionBlock)completionBlock
- (void)setVideoAtPath:(NSURL *)videoPathURL completionBlock:(ALAssetsLibraryWriteVideoCompletionBlock)completionBlock

如果资源被更新了还想看原来的资源怎么办,Apple已经帮我们想到这个问题了,originalAsset就是原始的资源。遗憾的是,如果我们更新了资源却没有存储,那就没办法找到原来的资源了。

ALAssetRepresentation是对 ALAsset 的封装,可以更方便地获取 ALAsset 中的资源信息,比如url、filename、scale等等。每个 ALAsset 都有至少有一个 ALAssetRepresentation 对象,可以通过 defaultRepresentation 获取。而例如使用系统相机应用拍摄的 RAW + JPEG 照片,则会有两个 ALAssetRepresentation,一个封装了照片的 RAW 信息,另一个则封装了照片的 JPEG 信息

其中fullScreenImage比较常用,就是返回一个屏幕大小的缩略图,比thumbnail大一些,但仍然是分辨率比较低的图片。但是这个很有用,因为它既满足了预览的清晰度要求,也加快了加载速度。

与之对应的是fullResolutionImage,它表示原分辨率的图片,当然是最清晰的版本,也是最大的,所以加载速度很慢。很少用到。

ALAssetsGroup就是相册,其顺序就是系统相册看到的顺序。
手机的每个相册都有一个预览图,是由posterImage属性指定的。

同样地,ALAssetsGroup也提供了的接口。

//增
// Returns YES if the asset was added successfully.  Returns NO if the group is not editable, or if the asset was not able to be added to the group.
- (BOOL)addAsset:(ALAsset *)asset;

//查
- (void)enumerateAssetsUsingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock
- (void)enumerateAssetsWithOptions:(NSEnumerationOptions)options usingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock
- (void)enumerateAssetsAtIndexes:(NSIndexSet *)indexSet options:(NSEnumerationOptions)options usingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock

其中,enumerateAssetsWithOptions:usingBlock:可以通过指定NSEnumerationReverse选项来倒序遍历相册。
ALAssetsGroupEnumerationResultsBlock处理资源,同上,可以指定stop=true来终止遍历。

Photos

The shared PHPhotoLibrary object represents the entire set of assets and collections managed by the Photos app, including both assets stored on the local device and (if enabled) those stored in iCloud Photos

官方建议,iOS8之后开始用Photos库来替代ALAssetLibrary库。Photos提供了额外的关于用户资源的元数据,而这些数据在以前使用 ALAssetsLibrary 框架中是没有办法访问,或者很难访问到。这点可以从PhotosTypes.h中看出来,比如可以验证资源库中的图像在捕捉时是否开启了 HDR;拍摄时是否使用了相机应用的全景模式;是否被用户标记为收藏或被隐藏等等信息。

Photos淡化照片库中 URL 的概念,改之使用一个标志符来唯一代表一个资源,即localIdentifier。其带来的最大好处是PHObject类实现了 NSCopying 协议,可以直接使用localIdentifier属性对PHObject及其子类对象进行对比是否同一个对象。

Photos提供了更全面的接口,涵盖了的所有方面。可以参考官方文档。这些操作都是基于相应的变更请求类PHAssetChangeRequest, PHAssetCollectionChangeRequestPHCollectionListChangeRequest,都在PhotoLibraryperformChanges:completionHandler:或者performChangesAndWait:error:changeBlock中执行。


每个change request的类中都提供了一个新增资源的方法:

//PHAssetChangeRequest
+ (instancetype)creationRequestForAssetFromImage:(UIImage *)image;
+ (nullable instancetype)creationRequestForAssetFromImageAtFileURL:(NSURL *)fileURL;
+ (nullable instancetype)creationRequestForAssetFromVideoAtFileURL:(NSURL *)fileURL;

//PHAssetCollectionChangeRequest
+ (instancetype)creationRequestForAssetCollectionWithTitle:(NSString *)title;

//PHCollectionListChangeRequest
+ (instancetype)creationRequestForCollectionListWithTitle:(NSString *)title;


每个change request的类中都提供了一个删除资源的方法:

//PHAssetChangeRequest
+ (void)deleteAssets:(id)assets;

//PHAssetCollectionChangeRequest
+ (void)deleteAssetCollections:(id)assetCollections;

//PHCollectionListChangeRequest
+ (void)deleteCollectionLists:(id)collectionLists;


创建change request之后,可以使用属性或者实例化方法来修改它代表的asset或者collection的相应特性。比如changeRequestForAsset: 方法可以根据目标asset创建一个 change request,然后可以修改favorite属性.

//PHAssetChangeRequest
+ (instancetype)changeRequestForAsset:(PHAsset *)asset;

//PHAssetCollectionChangeRequest
+ (nullable instancetype)changeRequestForAssetCollection:(PHAssetCollection *)assetCollection;
+ (nullable instancetype)changeRequestForAssetCollection:(PHAssetCollection *)assetCollection assets:(PHFetchResult *)assets;

//PHCollectionListChangeRequest
+ (nullable instancetype)changeRequestForCollectionList:(PHCollectionList *)collectionList;
&#43; (nullable instancetype)changeRequestForCollectionList:(PHCollectionList *)collectionList childCollections:(PHFetchResult<__kindof PHCollection *> *)childCollections;

官方文档给了一个创建asset添加到album的例子&#xff1a;

- (void)addNewAssetWithImage:(UIImage *)image toAlbum:(PHAssetCollection *)album {
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        PHAssetChangeRequest *createAssetRequest &#61; [PHAssetChangeRequest creationRequestForAssetFromImage:image];
        PHAssetCollectionChangeRequest *albumChangeRequest &#61; [PHAssetCollectionChangeRequest changeRequestForAssetCollection:album];
        PHObjectPlaceholder *assetPlaceholder &#61; [createAssetRequest placeholderForCreatedAsset];        [albumChangeRequest addAssets:&#64;[ assetPlaceholder ]];
     } completionHandler:^(BOOL success, NSError *error) {
        NSLog(&#64;"Finished adding asset. %&#64;", (success ? &#64;"Success" : error));
    }];
}

每个change request都有一个PHObjectPlaceholder类型的属性&#xff0c;其作用是给新创建的asset或者collection占位&#xff0c;可以在change block完成之后直接获取到新创建的资源。你也可以直接在change block里直接添加到change request中去。

每次在调用performChanges:completionHandler:或者 performChangesAndWait:error:方法时&#xff0c;Photos都可能尝试提醒用户访问相册权限。

你可以在一个change block合并提交多个change request


Photos中有两种资源可供获取&#xff1a;PHAsset 和 PHCollection。PHCollection有PHAssetCollection和PHCollectionList两个子类。获取资源的过程类似于Core Data:

/*PHAsset*/
&#43; (PHFetchResult *)fetchAssetsInAssetCollection:(PHAssetCollection *)assetCollection options:(nullable PHFetchOptions *)options;
&#43; (PHFetchResult *)fetchAssetsWithLocalIdentifiers:(NSArray *)identifiers options:(nullable PHFetchOptions *)options; // includes hidden assets by default
&#43; (nullable PHFetchResult *)fetchKeyAssetsInAssetCollection:(PHAssetCollection *)assetCollection options:(nullable PHFetchOptions *)options;
&#43; (PHFetchResult *)fetchAssetsWithBurstIdentifier:(NSString *)burstIdentifier options:(nullable PHFetchOptions *)options;
&#43; (PHFetchResult *)fetchAssetsWithOptions:(nullable PHFetchOptions *)options;
&#43; (PHFetchResult *)fetchAssetsWithMediaType:(PHAssetMediaType)mediaType options:(nullable PHFetchOptions *)options;
&#43; (PHFetchResult *)fetchAssetsWithALAssetURLs:(NSArray *)assetURLs options:(nullable PHFetchOptions *)options


/*PHAssetCollection*/
&#43; (PHFetchResult *)fetchAssetCollectionsWithLocalIdentifiers:(NSArray *)identifiers options:(nullable PHFetchOptions *)options;
&#43; (PHFetchResult *)fetchAssetCollectionsWithType:(PHAssetCollectionType)type subtype:(PHAssetCollectionSubtype)subtype options:(nullable PHFetchOptions *)options;
&#43; (PHFetchResult *)fetchAssetCollectionsContainingAsset:(PHAsset *)asset withType:(PHAssetCollectionType)type options:(nullable PHFetchOptions *)options;
&#43; (PHFetchResult *)fetchAssetCollectionsWithALAssetGroupURLs:(NSArray *)assetGroupURLs options:(nullable PHFetchOptions *)options;
&#43; (PHFetchResult *)fetchMomentsInMomentList:(PHCollectionList *)momentList options:(nullable PHFetchOptions *)options;
&#43; (PHFetchResult *)fetchMomentsWithOptions:(nullable PHFetchOptions *)options;

/*PHCollectionList*/
&#43; (PHFetchResult *)fetchCollectionListsContainingCollection:(PHCollection *)collection options:(nullable PHFetchOptions *)options;
&#43; (PHFetchResult *)fetchCollectionListsWithLocalIdentifiers:(NSArray *)identifiers options:(nullable PHFetchOptions *)options;
&#43; (PHFetchResult *)fetchCollectionListsWithType:(PHCollectionListType)collectionListType subtype:(PHCollectionListSubtype)subtype options:(nullable PHFetchOptions *)options;
&#43; (PHFetchResult *)fetchMomentListsWithSubtype:(PHCollectionListSubtype)momentListSubtype containingMoment:(PHAssetCollection *)moment options:(nullable PHFetchOptions *)options;
&#43; (PHFetchResult *)fetchMomentListsWithSubtype:(PHCollectionListSubtype)momentListSubtype options:(nullable PHFetchOptions *)options;

获取的结果PHAssetPHAssetCollectionPHCollectionList 都是轻量级的不可变对象&#xff0c;使用这些类时并没有将其代表的图像或视频或是集合载入内存中&#xff0c;要使用其代表的图像或视频&#xff0c;需要通过PHImageManager类来请求。


#pragma mark - Image
- (PHImageRequestID)requestImageForAsset:(PHAsset *)asset targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;
- (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset options:(nullable PHImageRequestOptions *)options resultHandler:(void(^)(NSData *__nullable imageData, NSString *__nullable dataUTI, UIImageOrientation orientation, NSDictionary *__nullable info))resultHandler;

#pragma mark - Live Photo
- (PHImageRequestID)requestLivePhotoForAsset:(PHAsset *)asset targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHLivePhotoRequestOptions *)options resultHandler:(void (^)(PHLivePhoto *__nullable livePhoto, NSDictionary *__nullable info))resultHandler PHOTOS_AVAILABLE_IOS_TVOS(9_1, 10_0);


#pragma mark - Video
- (PHImageRequestID)requestPlayerItemForVideo:(PHAsset *)asset options:(nullable PHVideoRequestOptions *)options resultHandler:(void (^)(AVPlayerItem *__nullable playerItem, NSDictionary *__nullable info))resultHandler;
- (PHImageRequestID)requestExportSessionForVideo:(PHAsset *)asset options:(nullable PHVideoRequestOptions *)options exportPreset:(NSString *)exportPreset resultHandler:(void (^)(AVAssetExportSession *__nullable exportSession, NSDictionary *__nullable info))resultHandler;
- (PHImageRequestID)requestAVAssetForVideo:(PHAsset *)asset options:(nullable PHVideoRequestOptions *)options resultHandler:(void (^)(AVAsset *__nullable asset, AVAudioMix *__nullable audioMix, NSDictionary *__nullable info))resultHandler;

iOS11的系统相册支持了GIF&#xff0c;这个时候或取GIF就要用requestImageDataForAsset了&#xff0c;否则是一张静图。

targetSize指定了图片的目标大小&#xff0c;但是结果不一定就是这个大小&#xff0c;还要以来后面options的设置&#xff1b; contentMode类似于UIView的contentMode属性&#xff0c;决定了照片应该以按比例缩放还是按比例填充的方式放到目标大小内。如果不对照片大小进行修改或裁剪&#xff0c;那么方法参数是 PHImageManagerMaximumSize 和 PHImageContentMode.Default。

PHImageRequestOptions提供了设置图片的其他一些属性。

deliveryMode指定了图片递送进度的策略&#xff1a;

  • PHImageRequestOptionsDeliveryModeOpportunistic 默认行为&#xff0c;同步获取时返回一个结果&#xff1b;异步获取时会返回多个结果&#xff0c;从低质量版本到高质量版本。
  • PHImageRequestOptionsDeliveryModeHighQualityFormat 只返回一次高质量的结果&#xff0c;可以接受长时间的加载。在同步模式下&#xff0c;默认直接采用这个策略。
  • PHImageRequestOptionsDeliveryModeFastFormat 只返回一次结果&#xff0c;但质量稍微差一点点&#xff0c;是前面两种策略的结合。

resizeMode指定了重新设置图片大小的方式&#xff1a;

  • PHImageRequestOptionsResizeModeNone 不用重新设置
  • PHImageRequestOptionsResizeModeExact 返回图像与targetSize一样&#xff0c;如果指定了normalizedCropRect&#xff0c;则必须设置为这个模式。
  • PHImageRequestOptionsResizeModeFast 已targetSize为参考&#xff0c;优化解码方式&#xff0c;效率更好一些&#xff0c;但结果可能比targetSize大。

normalizedCropRect原始图片的单元坐标上的裁剪矩形。只在 resizeMode 为 Exact 时有效。

networkAccessAllowed是否下载iCloud上的照片。

progressHandler下载iCloud照片的进度处理器。

version针对编辑过的照片决定哪个版本的图像资源应该通过 result handler 被递送。

  • PHImageRequestOptionsVersionCurrent 会递送包含所有调整和修改的图像。
  • PHImageRequestOptionsVersionUnadjusted 会递送未被施加任何修改的图像。
  • PHImageRequestOptionsVersionOriginal 会递送原始的、最高质量的格式的图像 (例如 RAW 格式的数据。而当将属性设置为 .Unadjusted 时&#xff0c;会递送一个 JPEG

当你需要加载许多资源时&#xff0c;可以使用PHCachingImageManager。比如当要在一组滚动的 collection 视图上展示大量的资源图像的缩略图时&#xff0c;预先将一些图像加载到内存中有时是非常有用的。

在缓存的时候&#xff0c;只是照片资源被缓存&#xff0c;此时还没有裁剪和大小设置&#xff1b;
如果同时对一个asset有多个不同options或targetSize的缓存请求时&#xff0c;采取FIFO的原则。

- (void)startCachingImagesForAssets:(NSArray *)assets targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options;
- (void)stopCachingImagesForAssets:(NSArray *)assets targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options;
- (void)stopCachingImagesForAllAssets;



推荐阅读
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 本文介绍了在iOS开发中使用UITextField实现字符限制的方法,包括利用代理方法和使用BNTextField-Limit库的实现策略。通过这些方法,开发者可以方便地限制UITextField的字符个数和输入规则。 ... [详细]
  • Vagrant虚拟化工具的安装和使用教程
    本文介绍了Vagrant虚拟化工具的安装和使用教程。首先介绍了安装virtualBox和Vagrant的步骤。然后详细说明了Vagrant的安装和使用方法,包括如何检查安装是否成功。最后介绍了下载虚拟机镜像的步骤,以及Vagrant镜像网站的相关信息。 ... [详细]
  • 本文介绍了解决mysql 5.1启动问题的方法,通过修改my.ini文件中的相关配置,包括innodb_data_home_dir和skip-innodb等,可以解决启动问题。同时还介绍了如何调整内存池来存储metadata信息。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
author-avatar
liuyidii
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有