我们都知道UIImage imageNamed:方法的神秘幕后缓存机制.在Apple的UIImage类参考中,它说:
在内存不足的情况下,可以从UIImage对象中清除图像数据以释放系统上的内存.此清除行为仅影响UIImage对象内部存储的图像数据,而不影响对象本身.当您尝试绘制其数据已被清除的图像时,图像对象会自动从其原始文件重新加载数据.然而,这个额外的负载步骤可能会导致很小的性能损失.
实际上,正如文档所示,图像数据不会"从UIImage对象中清除以释放系统上的内存".相反,应用程序会收到内存警告,直到它"因内存压力"退出.
编辑:在Xcode项目中使用传统的图像文件引用时,UIImage缓存工作正常.只是当您转换到资产目录时,内存永远不会被释放.
我实现了一个带有几个UIImageViews的UIScrollView来滚动浏览一长串图像.滚动时,正在加载下一个图像并将其分配给UIImageView的image属性,删除之前保存的UIImage的强链接.
由于imageNamed:缓存机制,我很快就耗尽了内存,应用终止时分配了大约170 MB的内存.
当然,有很多有趣的解决方案可以实现自定义缓存机制,包括覆盖imageNamed:类别中的类方法.通常,使用imageWithContentOfFile:不缓存图像数据的类方法,就像Apple开发人员在WWDC 2011上所建议的那样.
这些解决方案适用于常规图像文件,但您必须获得不像我希望的那样优雅的路径和文件扩展名.
我使用Xcode 5中引入的新资产目录,以利用根据设备和高效图像文件存储有条件地加载图像的机制.截至目前,似乎没有直接的方法从资产目录加载图像而不使用imageNamed:,除非我错过了一个明显的解决方案.
你们是否已经找到了资产目录的UIImage缓存机制?
我想在UIImage上实现一个类似于以下内容的类别:
static NSCache *_cache = nil;
@implementation UIImage (Caching)
+ (UIImage *)cachedImageNamed:(NSString *)name {
if (!_cache) _cache = [[NSCache alloc] init];
if (![_cache objectForKey:name]) {
UIImage *image = ???; // load image from Asset Catalog without internal caching mechanism
[_cache setObject:image forKey:name];
}
return [_cache objectForKey:name];
}
+ (void)emptyCache …Run Code Online (Sandbox Code Playgroud) 我正在FooSwift中实现一个类,它应该实例化给定子类的对象SuperBar,例如Bar: SuperBar.我非常喜欢Swift中的泛型,所以我试着用这种方式实现它:
class Foo<T: SuperBar> {
func instantiateObject() -> T {
return T()
}
}
class SuperBar {
}
class Bar: SuperBar {
}
let foo = Foo<Bar>()
let obj = foo.instantiateObject()
Run Code Online (Sandbox Code Playgroud)
您可以在Xcode Playground中运行代码片段并观察它obj是类型SuperBar而不是Bar,虽然它说Bar我在Alt单击常量名称时.
有任何想法吗?:)
虽然广告宣传Xcode 4了解共享工作区中的跨项目类项目,但我没有发现这有效并且对该问题进行了一些研究.在这里的许多线程中讨论的常见解决方案是创建一个静态库并将项目链接到它.
因此,我遵循了Jonah的指南(http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/)并创建了一个静态库来共享经常使用的子类UIView有多个项目.
通过一些试验和错误经验以及故障排除,我发现这个解决方案非常令人满意和干净,但仍然存在一些复杂情况:
(1)静态库无法共享XIB文件
在我做了研究之后,似乎无法从静态库项目外部访问XIB文件而不将它们拖入到创建引用所需的每个项目中.给定静态库中的UIViewController子类应该从XIB加载 - 尽管可以从任何链接静态库的项目访问UIViewController子类,但是如果不将XIB文件添加到该项目,则不能调用'initWithNibName'.
我只是通过在我需要的每个项目中创建对静态库的XIB文件的引用来暂时解决这个问题 - 有更好的解决方案吗?
(2)Interface Builder不知道静态库中的类
虽然我可以在我的静态库中选择UIView的一个子类作为我在项目中拖入XIB的对象的类(即使使用自动完成),但我在运行时遇到错误"Interface Builder中的未知类[UIViewSubclassName]"文件".
我在这里找到的解决方案 - Interface Builder无法在静态库中看到类 - (将头文件拖入XIB-Browser以使Interface Builder识别该类)显然已停止使用新的Xcode 4 - XIB-Browser是合并到单窗口界面,并不响应被拖入其中的头文件.
如何让我的XIB包含来自静态库的对象(例如我的项目中的UIViewController子类应包含我经常使用的一些按钮,因此包含在我的静态库中)而不会在运行时抛出异常?
非常感谢你!
PS:其中一些错误发生在编译模拟器没有问题的代码中,但在构建设备时抛出错误...
原始问题(见下面的解决方案):
我试图在我的Swift应用程序中使用AddressBook.framework,但无法弄清楚如何实现该ABAddressBookRegisterExternalChangeCallback功能.
在Objective-C中,我只是将回调实现为C函数并传递其指针:
// somewhere in the initializer of the MyAddressBook class:
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(nil, nil);
ABAddressBookRegisterExternalChangeCallback(addressBook, externalChangeCallback, (__bridge void *)(self));
// somewhere else in the MyAddressBook class:
void externalChangeCallback(ABAddressBookRef reference, CFDictionaryRef info, void *context)
{
[(__bridge MyAddressBook *)context addressBookDidChangeExternally];
}
- (void)addressBookDidChangeExternally
{
// good old Obj-C from here on!
}
Run Code Online (Sandbox Code Playgroud)
在Swift中,我很难处理C函数.我发现Apple增加了在beta 3中传递C函数指针的能力,但是我如何声明这样的函数呢?使用Swift的闭包语法会很好,但这是否可能?
这是我创建的地方ABAddressBookRef:
var addressBookRef: ABAddressBookRef = {
let addressBookRef: ABAddressBookRef = ABAddressBookCreateWithOptions(nil, nil).takeRetainedValue()
// TODO: how do …Run Code Online (Sandbox Code Playgroud) 说我有一个协议Fooable:
protocol Fooable {}
Run Code Online (Sandbox Code Playgroud)
现在我需要Fooable使用泛型函数中的类型:
func fooingAround<FooableType: Fooable>(withType: FooableType.Type) {}
Run Code Online (Sandbox Code Playgroud)
当我用一个Fooable类型调用函数时,这工作正常:
struct Foo: Fooable {}
fooingAround(Foo.self) // works fine
Run Code Online (Sandbox Code Playgroud)
但是,我需要Fooable从其他地方检索我交给函数的类型.这是编译器失败的地方:
let fooableType: Fooable.Type = // obtain from somewhere else
fooingAround(fooableType) // compiler error: "Cannot invoke 'fooingAround' with an argument list of type '(Fooable.Type)'"
Run Code Online (Sandbox Code Playgroud)
具体来说,我Fooable.Type从描述API端点的枚举中获取,其中每个端点由不同的Fooable类表示.
我想问题出现是因为我动态获取了一个类型,所以在编译时不能强类型.
有办法解决这个问题吗?