如何确定PHAsset
iOS设备上可用的最大图像大小,其中"可用"我的意思是当前在设备上,不需要从iCloud照片库进行任何网络下载?
我一直在开发一个应用程序,其中一组缩略图显示在UICollectionView
(很像照片应用程序),然后用户可以选择一个图像来查看它的全尺寸.如有必要,可从iCloud下载完整大小的图像.但是,我希望向用户显示图像的最大版本,直到完整大小可用.
Photos Framework的工作方式相当奇怪:
在集合视图中,我使用a PHCachingImageManager
来缓存(以及稍后请求)具有targetSize
186x186像素的图像(UICollectionViewCell
由于视网膜缩放而使尺寸加倍).
这非常有效,滚动非常快,并且在用图像填充单元格时没有延迟.检查返回图像的大小,它们大约是342x256像素.这是在我的iPhone 6上启用了iCloud Photo Library并启用了"优化存储",因此大多数图像只能在设备上存储小的缩略图.
然而,奇怪的是,如果我然后请求任何图像的完整尺寸(或更大)版本,使用PHCachingImageManager
或PHImageManager.defaultManager()
使用该PHImageRequestOptionsDeliveryMode.Opportunistic
选项,返回的第一个(低质量)图像是一个小的60x45像素邮票,看起来在全屏幕上可怕,直到最终下载完整尺寸的图像来替换它.
显然,在设备上更大的缩略图(342x256)已经,因为他们是在集合视图只是显示!那么为什么地狱不会将它们作为第一个"低质量"图像返回,直到下载完整尺寸?为了确保342x256图像确实已经在设备上,我在飞行模式下运行代码,因此没有发生网络访问.
我发现如果我要求任何大小高达256x256我会得到342x256图像返回.一旦我变大(甚至1个像素),它将首先返回60x45图像然后尝试下载全尺寸图像.
我已经更改了我的代码以首先发出256x256请求,然后是一个完整大小的请求PHImageRequestOptionsDeliveryMode.HighQualityFormat
(它不会返回一个微小的中间图像),并且工作得非常好.它也是iOS Photos应用程序必须要做的,因为它在下载完整图像时显示相对高质量的缩略图.
那么,在这样的背景下,我怎么知道设备图像尺寸最大的是PHAsset
什么?256x256是一个神奇的数字,还是取决于iCloud Photo Library如何优化空间(基于库的大小和可用的设备存储)?
当然,似乎是一个错误,照片框架没有返回当前可用的最大图像(当要求的尺寸大于目前的尺寸),并且要获得它拥有的最大尺寸,你必须要求这个尺寸或更小,因为如果你要求更大,你将获得60x45的缩影!离奇.
更新:提交给Apple的错误报告:https://openradar.appspot.com/25181601
演示该错误的示例项目:https://github.com/mluisbrown/PhotoKitBug
好的,我知道这System.getProperty("os.name")
会给我我正在运行的操作系统的名称,但这不是很多帮助.我需要知道的是,如果我运行的操作系统是一个类似Unix的操作系统,我不关心它是HP-UX,AIX,Mac OS X还是其他什么.
从可能的os.name值列表看起来像检测"类Unix"操作系统正在检查是否一个快速和肮脏的方式os.name
并没有包含的"Windows".给我的误报是操作系统,我的代码不太可能遇到!不过,如果有的话,我很想知道更好的方法.
我已经查看了iOS StoreKit中与"无法连接到iTunes商店"相关的许多现有问题,我认为我的情况不包括在内:
在iOS模拟器中运行时,恢复之前购买的应用内购买后出现"无法连接到iTunes商店"错误.如果我点击取消,则弹出窗口消失,恢复成功.
购买应用内购买时,只有在恢复时才会出现问题.
此外,问题只出现在模拟器上,而不是在真正的iPhone上进行测试时.
我很确定一切都好,只是想确认它只是一个模拟器错误.还有谁见过这个?
我有一个应用程序,它进行前向地理编码(获取给定地址的坐标)以显示一堆引脚MKMapView
.该应用程序是在iOS支持前向地理编码之前开发的CLGeocoder
(首先在iOS 5中提供).因此,我的应用程序使用Google Maps Geocoding API,这通常非常准确.给定一个带有街道号码的完整地址,它通常会在几米内为您提供该地址的确切位置.
我正在对我的应用程序进行一些更新以支持iOS 6,并决定从使用Google API切换到使用,CLGeocoder
只要该应用程序在iOS 5或更高版本上运行.然而,在我的测试中(所有地址都在葡萄牙,我居住的地方),它是如此不准确,以至于完全无法使用.
我使用的– geocodeAddressString:completionHandler:
,例如,给出的地址"自由大道195,里斯本,葡萄牙"它给了我一个"自由大道"在城市辛特拉,不葡京(里斯本)的.距离真实地址约15公里.Avenida da Liberdade是里斯本最大和最着名的大道之一.相当于纽约市的第五大道.这不是一些不起眼的小街道.
有没有什么我做错了得到如此可怕的准确性?其他人是否有类似的准确性问题,特别是在美国以外的地址?
目前看来我必须坚持使用Google Maps API.顺便说一句,我一直在使用iOS 6模拟器,结果并没有更好.将相同的搜索字符串放入iOS 6地图应用程序的搜索框中会产生完全不准确的结果.
编辑:添加CLGeocoder
代码:
CLGeocoder *fgeo = [[[CLGeocoder alloc] init] autorelease];
NSLog(@"Geocoding for Address: %@\n", address);
[fgeo geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
if (!error) {
// do stuff with the placemarks
for (CLPlacemark *placemark in placemarks) {
NSLog(@"%@\n %.2f,%.2f",[placemark description], placemark.location.horizontalAccuracy, placemark.location.verticalAccuracy);
}
} else {
NSLog(@"Geocoding error: %@", [error …
Run Code Online (Sandbox Code Playgroud) 注意到我的MacBook Air上的可用空间显着减少(并且只有128GB,每GB计数!)我运行DaisyDisk以查明发生了什么,并发现该~/Library/Application Support/iPhone Simulator/6.1/tmp
目录有3GB的垃圾(ghostlyIcons.,gridImages., iconImages.*,iconLabels_gray.*)在里面!
从它看起来3GB是没有什么,该文件夹可以轻松架50GB!
我想我可以删除那里的东西吗?不应该自动删除吗?
我有UITableView
一个UITextField
在每个UITableViewCells
.我在我的ViewController中有一个方法,它处理每个单元格的文本字段的"Do End On Exit"事件,我想要做的是用新文本更新我的模型数据.
我现在拥有的是:
- (IBAction)itemFinishedEditing:(id)sender {
[sender resignFirstResponder];
UITextField *field = sender;
UITableViewCell *cell = (UITableViewCell *) field.superview.superview.superview;
NSIndexPath *indexPath = [_tableView indexPathForCell:cell];
_list.items[indexPath.row] = field.text;
}
Run Code Online (Sandbox Code Playgroud)
当然做起field.superview.superview.superview
作用,但它似乎是如此hacky.有更优雅的方式吗?如果我设置的标签UITextField
到indexPath.row
其在细胞中的cellForRowAtIndexPath
意志标签总是甚至插入和删除行后是正确的?
对于那些密切关注的人,你可能会认为我有一个.superview
太多,而对于iOS6,你是对的.但是,在iOS7中,在单元格的内容视图和单元格本身之间的层次结构中有一个额外的视图(NDA阻止我形成详细说明).这恰恰说明了为什么做superview的事情有点hacky,因为它取决于知道如何UITableViewCell
实现,并且可以打破操作系统的更新.
我使用的是UIImagePickerController
具有allowsEditing
能够在共享一个应用程序的图像,却发现裁剪的图像用于运行iOS仅11偏移的设备.
我的UIImagePickerControllerDelegate
实现非常简单,只是标准操作:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerEditedImage] as! UIImage
imageView.image = image
picker.dismiss(animated: true, completion: nil)
}
Run Code Online (Sandbox Code Playgroud)
下面你可以看到差异.iOS 10在右侧,iOS 11在左侧.您可以看到iOS 11图像向下偏移,即使裁剪矩形放在完全相同的位置.
这里是一个视频演示该问题:https://www.dropbox.com/s/4csofidjcrc9ah6/UIImagePickerControllerEditedImageOffset.mp4?dl=0
我还在GitHub上创建了一个演示项目来演示这个问题:https://github.com/aivars/photo-Picker-Tests
我猜这是UIImagePickerController
错误,但想知道为什么不在网上找到任何其他错误报告.
我还向Apple提交了一份错误报告:http://www.openradar.me/36292067
根据文档,如果使用默认值,useProtocolCachePolicy
逻辑如下:
- 如果该请求不存在缓存的响应,则 URL 加载系统将从原始源获取数据。
- 否则,如果缓存的响应没有指示每次都必须重新验证,并且缓存的响应不是过时的(超过其过期日期),则 URL 加载系统将返回缓存的响应。
- 如果缓存的响应已过时或需要重新验证,则 URL 加载系统会向原始源发出 HEAD 请求,以查看资源是否已更改。如果是,则 URL 加载系统从原始源获取数据。否则,它返回缓存的响应。
然而,我的实验(见下文)表明这是完全错误的。即使响应被缓存,它也永远不会被使用,也不会发出HEAD
任何请求。
我正在向一个返回的 URL 发出请求,ETag
并且Last-Modified
标头永远不会改变。我至少发出过一次请求,因此响应已被缓存(我可以通过查看 iOS 模拟器上应用程序的缓存数据库来验证这一点)
useProtocolCachePolicy
(默认)如果我将URLSession
with设置为URLSessionConfiguration
,则响应将被缓存(我可以在缓存数据库中看到它),但缓存的响应永远不会被使用。对同一 URL 的重复请求始终会发出不带或标头的新请求,因此服务器始终返回 HTTP 200 和完整响应。缓存的响应将被忽略。requestCachePolicy
useProtocolCachePolicy
GET
If-None-Match
If-Modified-Since
reloadRevalidatingCacheData
每个URLRequest
如果我将每个cachePolicy
设置为,那么我会看到缓存正在运行。每次发出请求时,都会发出请求,并将和标头分别设置为缓存响应的和标头的值。由于没有任何变化,服务器以 进行响应,并将本地缓存的响应返回给调用者。 URLRequest
reloadRevalidatingCacheData
GET
If-None-Match
If-Modified-Since
ETag
Last-Modified
304 Not Modified
reloadRevalidatingCacheData
在URLSessionConfiguration
如果我只 …
在本节末尾的"勇敢与真实的Clojure"中,减少了一个挑战:
如果你想要一个真正让你的头发恢复的运动,请尝试
map
使用reduce
事实证明,这比我想象的要困难得多(至少对我来说是一个Clojure初学者).经过几个小时,我想出了这个:
(defn map-as-reduce
[f coll]
(reduce #(cons (f %2) %1) '() (reverse coll)))
Run Code Online (Sandbox Code Playgroud)
这是一个更好的方法吗?我特别感到沮丧的是,我必须反转输入集合才能使其正常工作.它似乎有点不雅!
我刚刚使用Xcode 8 beta将我的项目从Swift 2.2迁移到Swift 3.0.
我有类似下面的代码(您可以将其粘贴到游乐场):
import Foundation
let datesWithCount: [(Date, Int)] = [(Date(), 1), (Date(), 2), (Date(), 3)]
let dates: [Date] = datesWithCount.sorted {
$0.0 < $1.0
}.prefix(1).map {
return $0.0
}
Run Code Online (Sandbox Code Playgroud)
在Swift 2.2中编译好了.但是,使用Swift 3.0我得到了错误
模糊地使用'前缀'
在Swift 3.0中编译它的唯一方法是将地图拆分为一个单独的行:
let sortedDatesWithCount = datesWithCount.sorted {
$0.0 < $1.0
}.prefix(1)
let mappedDates = sortedDatesWithCount.map {
return $0.0
}
Run Code Online (Sandbox Code Playgroud)
顺便说一句,在实际的代码中我NSNotification
从map
非Date
s 返回对象,但错误是相同的.我刚刚Date
在这里用来使这个例子变得简单.
有没有办法让这个编译成一个班轮?
更新:为Swift项目创建了一个JIRA.
ios ×5
caching ×1
clojure ×1
geocoding ×1
ios11 ×1
ios5 ×1
iphone ×1
java ×1
map-function ×1
phasset ×1
photokit ×1
storekit ×1
swift ×1
swift3 ×1
uiimage ×1
uiimageview ×1
uitableview ×1
unix ×1
urlsession ×1
xcode8 ×1