创建一个简单的实用程序类
我想创建一个类来加速诸如获取应用程序委托、解析 xml 之类的事情,
将实用程序实现为类函数似乎很有意义。毕竟它实际上只是一个我们可以全局调用的函数。
但当我这样做时,
[xmlParser setDelegate:self];
我就有麻烦了。在类函数中, self 引用该类。
如果您是 Objective-C 程序员,那么优雅的解决方案是什么?
如果我将 (void)parseXMLFileAtURL:(NSString *)URL
转换为实例变量,那么事情看起来就不正确。 BNUtilitiesQuick 甚至没有字段,我真的很想拥有可以在任何地方访问的东西。
如果我将 BNUtilitiesQuick 作为 NSObject 的类别,这看起来很尴尬。为什么我的程序中的所有类都可以成为 XMLParser 的委托
那么我该怎么办?
@implementation BNUtilitiesQuick
+ (BadgerNewAppDelegate *)appDelegate
{
return [[UIApplication sharedApplication] delegate];
}
+ (NSManagedObjectContext*)managedObjectContext;{
return [[BNUtilitiesQuick appDelegate] managedObjectContext];
}
+ (void)parseXMLFileAtURL:(NSString *)URL {
//you must then convert the path to a proper NSURL or it won't work
NSURL *xmlURL = [NSURL URLWithString:URL];
// here, for some reason you have to use NSClassFromString when trying to alloc NSXMLParser, otherwise you will get an object not found error
// this may be necessary only for the toolchain
NSXMLParser* xmlParser = [[[NSXMLParser alloc] initWithContentsOfURL:xmlURL] autorelease];
// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
[xmlParser setDelegate:self];
// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
[xmlParser setShouldProcessNamespaces:NO];
[xmlParser setShouldReportNamespacePrefixes:NO];
[xmlParser setShouldResolveExternalEntities:NO];
[xmlParser parse];
}
@end
I want to create a class to speed up things like getting application delegate, parsing xml
Implementing the utilites as class function seems to make sense. After all it's effectively just a function we could call globally.
But then when I do
[xmlParser setDelegate:self];
I am in trouble. In a class function, self refer to the class.
What would be the elegant solution for this if you're an objective-c programmer
If I turn (void)parseXMLFileAtURL:(NSString *)URL
into an instance variable, then things don't look right. BNUtilitiesQuick doesn't even have a field and I really intent to have something that can be accessed anywhere.
If I turn BNUtilitiesQuick as categories of NSObject, that seems awkward. Why would all classes on my program can be the delegate of XMLParser
So what should I do?
@implementation BNUtilitiesQuick
+ (BadgerNewAppDelegate *)appDelegate
{
return [[UIApplication sharedApplication] delegate];
}
+ (NSManagedObjectContext*)managedObjectContext;{
return [[BNUtilitiesQuick appDelegate] managedObjectContext];
}
+ (void)parseXMLFileAtURL:(NSString *)URL {
//you must then convert the path to a proper NSURL or it won't work
NSURL *xmlURL = [NSURL URLWithString:URL];
// here, for some reason you have to use NSClassFromString when trying to alloc NSXMLParser, otherwise you will get an object not found error
// this may be necessary only for the toolchain
NSXMLParser* xmlParser = [[[NSXMLParser alloc] initWithContentsOfURL:xmlURL] autorelease];
// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
[xmlParser setDelegate:self];
// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
[xmlParser setShouldProcessNamespaces:NO];
[xmlParser setShouldReportNamespacePrefixes:NO];
[xmlParser setShouldResolveExternalEntities:NO];
[xmlParser parse];
}
@end
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
有多种方法可以解决您对
BNUtilitiesQuick
的疑虑。您遇到麻烦的主要原因是 NSXMLParser 使用回调机制。这样做是为了让您不必立即将整个文档读入内存——它会边解析边解析。这意味着您创建的每个 NSXMLParser 都需要一个唯一的委托对象。
解决方案#1 - 使用单例模式
BNUtilitiesQuick
可以是单例,但是那么如果从两个不同的线程调用它两次就会遇到问题(该类将从同时解析的两个 XML 文档获取消息)。如果线程不是问题,那么这会起作用。解决方案 #2 - 切换 XML 解析器(避免该问题)
另一种解决方案是使用不需要基于委托的解析方法的不同 XML 解析器。 NSXMLParser是基于SAX的,通常使用回调或委托模式。 Ray Wenderlich 有一个很棒的 在他的博客上发布关于 iOS 上可用的不同 XML 解析器以及如何选择您最喜欢的解析器的文章。
解决方案 #3 - 在方法中创建委托对象
添加另一层抽象 - 您的解析 XML 方法应该创建新的 XML 解析器委托类的新实例,该类将处理此特定解析操作的回调。然后,当您创建解析器时,将委托设置为这个新创建的对象,并解析 XML。
Utils 类中不存储任何状态,因此您不必担心多线程问题。
它还可能有助于在解析方法中返回解析的对象而不是
(void)
——这似乎是设计的另一个陷阱。There are several ways to address your concerns with
BNUtilitiesQuick
.The primary reason you're having trouble is because NSXMLParser uses a callback mechanism. This is done so that you don't have to read the entire document into memory at once -- it parses as it goes. This means you need a unique delegate object for each NSXMLParser you create.
Solution #1 - use Singleton pattern
BNUtilitiesQuick
could be a singleton, but then you will run into issues if you call it twice from two different threads (the class will get messages from both XML documents that are being parsed simultaneously). If threading isn't an issue, this would work.Solution #2 - Switch XML parsers (avoid the problem)
Another solution would be to use a different XML parser that doesn't require a delegate-based parsing approach. NSXMLParser is SAX-based, which generally uses a callback or delegate pattern. Ray Wenderlich has a great post on his blog about the different XML parsers available on iOS and how to choose your favorite.
Solution #3 - Create the delegate object in the method
Add another layer of abstraction -- your parse XML method should create a new instance of a new XML Parser Delegate class that will handle callbacks for this specific parse operation. Then, when you create the parser, set the delegate to this newly created object, and parse the XML.
No state is stored on your Utils class, so you don't have to worry about multi-threaded issues.
It might also help to return the parsed object instead of
(void)
in your parse method -- that seems like another pitfall of your design.