带有 NSOperations 的 iOS 应用架构

发布于 2024-09-26 04:24:14 字数 2546 浏览 0 评论 0原文

两个月前,我开始编写一个新的 iPhone 应用程序,因此我创建了一个通用的 RESTFul Web 服务,它允许我拥有许多必要的功能,例如用户身份验证、用户配置文件、友谊系统、媒体处理、消息传递系统等。在我看来,有几个用例可以在未来的 iPhone 应用程序中重用此 Web 服务。

出于这种心态,我决定为此应用程序(以及所有未来的应用程序)编写一个静态库,用于处理所有繁重的工作,例如媒体(图像、视频、声音)设置和处理、与 Web 服务通信、解析和映射结果的处理、CoreData 的处理等。

鉴于我的应用程序,存在大量并行任务正在运行的情况(最坏的情况),例如 用户当前更改了他/她的个人资料图片,同时应用程序将用户位置发送到服务器(在后台)并收到新的推送通知。

因此决定将每个逻辑操作(如SendUserLocation或GetCurrentFriendList)封装在一个NSOperation中,并将它们添加到一个serviceQueue(NSOperationQueue)中。

当操作成功从 Web 服务获取结果并立即处理它时,每个操作都能够生成子任务。

alt text

典型的 ServiceManager 方法如下所示

- (void)activateFriendsSync:(id)observer onSuccess:(SEL)selector {
    ELOSyncFriends *opSyncFriends  = [[ELOSyncFriends alloc] initWithSM:self];
    [self ELServiceLogger:opSyncFriends];
    [serviceQueue addOperation:opSyncFriends];
    if(observer) {
        [self registerObserver:observer selector:selector name:opSyncFriends.notificationName]; 
    }
}

每个操作、请求(到服务器)和子任务都使用 GUID 作为 notificationName处理完成后通知父对象。如果操作中的所有操作均已完成,它会将通知发送回用户界面。

也就是说,添加和删除子任务的代码如下所示

- (void)removeSubTask:(NSNotification*)notification {
    ELRequest *request = (ELRequest*)[notification object];
    [subTasks removeObjectIdenticalTo:request.notificationName];
    if([subTasks count] == 0) {
         // all SubTaks done, send notification to parent
        [serviceManager.notificationCenter postNotificationName:self.notificationName object:request];
    }
}

- (NSString*)addSubTask {
    NSString* newName = [self GetUUID];
    [subTasks addObject:[newName retain]];
    [serviceManager.notificationCenter addObserver:self selector:@selector(removeSubTask:) name:newName object:nil];
    return newName;
} 

- (NSString *)GetUUID {
    CFUUIDRef theUUID = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, theUUID);
    CFRelease(theUUID);
    return [(NSString *)string autorelease];
}

现在我所要做的就是在我的 gui 中调用 serviceManager 来启动特定操作,例如

[self.core.serviceManager activateFriendsSync:nil onSuccess:nil];

如果我想注册一个观察者,我只需传递一个观察者对象并像这样的选择器

[self.core.serviceManager activateFriendsSync:self onSuccess:@selector(myMethod:)];

最后但并非最不重要的我的问题:“架构”运行得非常好且稳定,但是值得这样做吗?它会产生太多开销吗?这还有道理吗?您个人是如何实现并发操作的?

最好的 亨利克·

P.S.请随意编辑我的问题,提出问题(作为评论),为我的想法命名。

我真的很难解释它,主要是因为我不是以英语为母语的人。别误会我的意思。我写这篇文章并不是为了以任何形式炫耀。我想做的就是学习(也许写一个更高级的 iphone / Objective C 问题)

Two month ago I started to write a new iPhone Application and for this reason I created a generic RESTFul web service, which allows me to have a lot of these necessary features like user authentication, user profiles, a friendship system, media processing, a messaging system and so on. In my mind there are several use cases to reuse this webservice for future iPhone applications.

With this state of mind, I decided to write a static library for this application (and all future apps) that handles all the heavy lifting like media (image, video, sound) setup and processing, communicating with the web service, parsing and mapping of the results, handling CoreData and so on.

Given my application there are scenarios when a lot of parallel tasks are running (worst case) e.g.
the user currently changes his/her profile picture, while the application sends the users location to the server (in the background) and a new push notification is received.

So decided to encapsule each logical operation (like SendUserLocation or GetCurrentFriendList) in a NSOperation and add them to a serviceQueue (NSOperationQueue).

Each Operation is able to spawn subtasks when the operation successfully got a result from the webservice and should process it now.

alt text

A typical ServiceManager method looks like

- (void)activateFriendsSync:(id)observer onSuccess:(SEL)selector {
    ELOSyncFriends *opSyncFriends  = [[ELOSyncFriends alloc] initWithSM:self];
    [self ELServiceLogger:opSyncFriends];
    [serviceQueue addOperation:opSyncFriends];
    if(observer) {
        [self registerObserver:observer selector:selector name:opSyncFriends.notificationName]; 
    }
}

Each operation, request (to the server) and subTask uses a GUID as a notificationName to notify the parent object when it's done processing. If everything in an operation is done, it sends a notification back to the user interface.

That said, the code for adding and removing subtasks looks like this

- (void)removeSubTask:(NSNotification*)notification {
    ELRequest *request = (ELRequest*)[notification object];
    [subTasks removeObjectIdenticalTo:request.notificationName];
    if([subTasks count] == 0) {
         // all SubTaks done, send notification to parent
        [serviceManager.notificationCenter postNotificationName:self.notificationName object:request];
    }
}

- (NSString*)addSubTask {
    NSString* newName = [self GetUUID];
    [subTasks addObject:[newName retain]];
    [serviceManager.notificationCenter addObserver:self selector:@selector(removeSubTask:) name:newName object:nil];
    return newName;
} 

- (NSString *)GetUUID {
    CFUUIDRef theUUID = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, theUUID);
    CFRelease(theUUID);
    return [(NSString *)string autorelease];
}

Now all I've got to do is to call the serviceManager in my gui to start a specific operation like

[self.core.serviceManager activateFriendsSync:nil onSuccess:nil];

If I want to register an observer, I just pass an observer object and a selector like this

[self.core.serviceManager activateFriendsSync:self onSuccess:@selector(myMethod:)];

Last but not least my question(s): The "architecture" runs very well and stable, but is it worth doing? Does it create too much overhead? Does it even make sense? How you, personally, implement concurrent operations?

Best
Henrik

P.S. Feel free to edit my question, ask questions (as a comment), call me names for this thinking.

I really had a hard time explaining it, basically because I'm not a native english speaker. And don't get me wrong. I didn't write this posting to show off in any kind. All I want to do is learn (and maybe to write a more advanced iphone / objective c question)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

成熟的代价 2024-10-03 04:24:14

是的,如果它被外包给服务请求,并且您有很多调用要做,那么这样的库并不是(我认为)矫枉过正,而且我已经写了类似的东西。这种结构使我能够轻松地管理一个复杂的系统,以及非常复杂和多样的任务。

我所做的主要设计差异是将 NSNotification 与服务管理器一起使用。相反,我更喜欢使用回调协议/类型(操作保存对其的引用)。 NSNotification 相当重。在这种情况下,该操作不会保留侦听器/通知对象,但侦听器会保留该操作。如果关系是 1-1,则允许取消。

另一个主要考虑因素是尽早定义线程。允许客户端定义他们想要在哪个线程上接收响应。这样做的原因是,如果通知/侦听器必须更新 UI(例如,您正在使用 UIKit 或 AppKit),回调通常会存在约束或逻辑条目。因此,创建者可以对操作说“你必须从主线程通知我”,或者“我可以处理来自任何线程的响应”。这将大大减少控制器/侦听器/观察器代码和出错的机会。

yes, if it's being farmed out to service requests and you have many calls to make, then such a library is not (imo) overkill, and i have written something similar. this structure made it very easy for me to manage a complex system, with very complex and varied tasks.

the primary design difference i made was not to use NSNotification with a service manager. instead, i favored using protocols/types for callbacks (which the operation holds a reference to). NSNotification is quite heavy. in this case, the operation does not retain the listener(s)/notified objects, but the listeners retain the operation. if the relation is 1-1, then allow cancellation.

another major consideration is to define threading early on. allow clients to define which thread they want to receive their response on. the reason for this is that there is often a constraint or logical entry for the callback if the notified/listener must update the UI (e.g., you're using UIKit or AppKit). therefore, the creator can say to the operation 'you must inform me from the main thread', or 'i can handle the response from any thread'. this will reduce your controller/listener/observer code and chance for errors greatly.

我一直都在从未离去 2024-10-03 04:24:14

对于“子操作”:如何将它们放入队列中,父操作是其每个子操作的依赖项(参见 -[ NSOperation addDependency: ])运营? NSOperationQueue 可以为您排序整个操作堆。我认为这使用起来简单且自然。

For "sub operations": what about putting them on your queue, with the parent operation being a dependency (cf. -[ NSOperation addDependency: ]) of each of its child operations? The NSOperationQueue can sequence your whole pile of operations for you. I think this is simple and natural to work with.

缺⑴份安定 2024-10-03 04:24:14

您刚刚描述了我在一些应用程序中使用的非常相似的架构:)

我让我的服务管理器层立即返回一组对象,然后在一段时间后返回更新的集合,即

NSArray *stuff = [serviceManager getFriendsForUser:@"Bob"];

,然后在服务器完成之后响应后,会收到一个 NSNotification,其中包含更新的列表(在本例中为 Bob 的朋友列表)。

除了这个微小的变化之外,您的架构是相同的!

完成所有设置需要做很多工作,但我认为从长远来看这是值得的,因为修复错误/扩展代码要容易得多。

You have just described a very similar architecture that I'm using in a few of my apps :)

I have my service manager layer returning a set of objects instantly and then returning an updated set after a while i.e.

NSArray *stuff = [serviceManager getFriendsForUser:@"Bob"];

and then, after the server has responded, an NSNotification is received that contains an updated list (of friends for Bob in this case).

Apart from this tiny change, your architecture is the same!

It is quite a lot of work to get it all set up but I think it's worth it in the long run as fixing bugs / extending the code is much easier.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文