iOS 瓶颈:全局变量与核心数据或属性列表

Posted

技术标签:

【中文标题】iOS 瓶颈:全局变量与核心数据或属性列表【英文标题】:iOS Bottleneck: Global variable vs. Core Data or Properity Lists 【发布时间】:2012-11-16 22:06:09 【问题描述】:

我是 ios 和 Cocoa 的新手。我的问题不是关于如何让某件事情发挥作用,而是更多关于改进用户体验和性能的设计。

我正在向现有应用添加功能。目前,该应用程序有一个类“RootViewController”(RVC),负责发出服务器请求。 RVC 调用服务器以获取 json 响应。这个 json 响应被解析,解析后的响应被一个名为“array”的 NSArray 对象引用。服务器提供给“array”的数据必须定期更新,因为它代表了其他客户可以购买的实时库存。

我需要在应用程序生命周期的不同时间在其他类中使用对“数组”的引用。我不想每次想使用或更新“数组”时都调用服务器。在我自己的设备上测试这个应用程序时,调用服务器似乎很慢 -> 会损害应用程序的性能。

我考虑过创建一个可以充当委托的类来保持对 NSArray 的引用 - 有点像全局变量。我会向服务器发出一个异步请求,并跟上这个委托类中的响应。我不确定如何确定这种方法是否有效或是否考虑最佳实践(考虑到 MVC)。

我正在寻找存储“数组”的最佳位置,以便其他类可以快速使用它,而无需过多依赖网络或内存使用情况。 “阵列”必须能够偶尔从服务器更新(因为“模型”可能会因库存变化而改变)。根据我的研究,iOS 的 CoreData 似乎是最好的起点,但如果应用程序不活跃,我不确定如何定期更新 CoreData。换句话说,如果 CoreData 中的数据最近没有更新,我不想向用户呈现陈旧的数据。

json 响应大小约为 20KB - 45KB。

存放轻量级对象以便定期更新的最佳/替代位置在哪里?我倾向于会话样式变量,但我不知道是否有更好的方法来做到这一点。

【问题讨论】:

首先,我怀疑这是 瓶颈。如果您是初学者,您的代码质量可能会比 CoreData 与 plist 的使用更能影响性能。 【参考方案1】:

根据 MVC 来看这个,你有两个部分:

一个数组——这是模型 从服务器获取库存的代码 - 这是控制器

这个控制器代码实际上是模型控制器,而不是视图控制器。我不会把它放在视图控制器类中。如果代码非常简单,您可以将其放在您的应用委托中,但我建议将其完全放在自己的类中。

-applicationDidFinishLaunching中:

[[InventoryController sharedInstance] reloadContent];
[[InventoryController sharedInstance] scheduleUpdates];

InventoryController.h

@interface InventoryController

@property (retain) NSArray *inventory;
@property (retain) NSTimer *reloadTimer;

+ (InventoryController *) sharedInstance;
- (void) reloadContent;
- (void) scheduleUpdates;

@end

InventoryController.m

@implmentation InventoryController

- (void) reloadContent 
    ...


+ (InventoryController *) sharedInstance 
    static InventoryController * singleton;
    if (!singleton)
        singleton = [[self.class alloc] init];
    return singleton;


- (void) scheduleUpdates 
    self.reloadTimer = ...;


@end

其他地方:

NSArray *inventory = [[InventoryController sharedInstance] inventory];

-reloadContent 中,您应该从服务器拉取内容。在-scheduleUpdates 中,您应该设置一个作用于控制器的计时器,使其定期重新加载数据。如果您的视图控制器需要在数据过期时调整其行为,请在数组旁边存储一个 NSDate,添加一个类似 -isStale 的方法来检查日期,然后首先调用它。

记得在后台加载 URL。您不应该在处理事件或操作时停止并重新加载数据,因此本质上,您的视图控制器需要在等待数据时从操作方法返回,并在您获取数据时调整其显示。

如果视图控制器需要在数据刷新后做出响应,让视图控制器注册一个通知,您可以在库存控制器完成更新其内容时发布该通知:

    [[NSNotificationCenter defaultCenter]
    postNotificationName:InventoryControllerDidReloadContent
                  object:self];

如果您想在设备上缓存库存数据,以便在应用程序进入后台时将其从内存中删除,您可以通过将数组写入属性列表来实现,但如果陈旧数据没有用处,你可能不想打扰。

您可以使用 Core Data 来代替数组和属性列表,但它并没有消除对从服务器加载数据并将其加载到上下文中的控制器的需要。您可能会有一个托管对象上下文和一个获取的结果控制器,而不是一个数组。如果您不在应用程序中编辑该内容,我怀疑 Core Data 是否会比数组和属性列表提供任何好处。

【讨论】:

【参考方案2】:

我建议将其存储在您的应用程序委托中。它可以很好地存储数组,并且可以从应用程序中的任何类访问。

【讨论】:

【参考方案3】:

如果这个“数组”有有趣的结构,CoreData 是一个不错的选择。在这种情况下,我猜测 CoreData 和 plist 的速度将彼此一样快。使用看起来最简单的一个,如果太慢,请尝试另一个。

尽量不要在应用未运行时更新数据。将上次更新时间与您的缓存数据一起存储。如果它“太旧”,则显示“请稍候”占位符并更新它。如果它是“旧但不太旧”,则显示您拥有的内容并在非主线程中更新它。或者尝试该 UI 的其他变体(“太旧”== 通知 + 只读模式)。

如果您确实发现了通过应用审核通过后台更新的技巧,请仔细考虑一下这会消耗多少用户电池。添加一种禁用它的方法。或者默认禁用它并添加一种启用它的方法。或者干脆不做。 :-)

【讨论】:

以上是关于iOS 瓶颈:全局变量与核心数据或属性列表的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript全局变量与局部变量

与全局'var'不同,javascript'let'全局变量不是'window'的属性[重复]

nodejs学习笔记 -- 全局对象与全局变量

JS全局变量是全局对象的属性,函数局部变量为啥就不是函数的属性呢?

Vue总结第六天:Vuex (全局变量管理~多个页面共享数据)

核心数据类的全局变量(坏?好?)