[Cocoa]_[Plug-in]

来源:互联网 发布:kindle有必要买吗 知乎 编辑:程序博客网 时间:2024/06/06 17:09

Plug-in

Plug-in即插件,一种扩展程序新特性而不需要改变主程序代码的方式。

创建Plug-in结构

创建plug-in的三种方式:

  • Plug-ins 实现一个正式协议
  • Plug-ins 从一个非正式协议实现一些方法
  • Plug-ins 继承一个抽象类或者具体基础类

发布一个正式Plug-ins协议

如果要使用自己声明的插件协议,只需要在头文件种声明协议即可。如下列:

/*   MyGreatImageApp   Graphics Filter Interface version 0   MyAppBitmapGraphicsFiltering.h*/#import <Cocoa/Cocoa.h>@protocol MyGreatImageAppBitmapGraphicsFiltering// Returns the version of the interface you're implementing.// Return 0 here or future versions may look for features you don't have!- (unsigned)interfaceVersion;// Returns what to display in the Filter menu.- (NSString *)menuItemString;// The main worker bee: filters the bitmap and returns a modified version.- (NSBitmapImageRep *)filteredImageRep:(NSBitmapImageRep *)imageRep;// Returns the window controller for the settings configuration window.- (NSWindowController *)configurationWindowController;@end

发布一个非正式Plug-ins协议

非正式协议比正式协议要复制一点,主要是有些方法是可选的,有些方法是必须,例子如下:

/*   MyGreatImageApp   Graphics Filter Interface version 0   MyAppBitmapGraphicsFiltering.h*/#import <Cocoa/Cocoa.h>@interface NSObject(MyGreatImageAppBitmapGraphicsFiltering)// REQUIRED// Returns the version of the interface you're implementing.// Return 0 here or future versions may look for features you don't have!- (unsigned)interfaceVersion;// OPTIONAL// Returns what to display in the Filter menu. Defaults to the plug-in// filename without the extension.- (NSString *)menuItemString;// REQUIRED// The main worker bee: filters the bitmap and returns a modified version.- (NSBitmapImageRep *)filteredImageRep:(NSBitmapImageRep *)imageRep;// OPTIONAL// Returns the window controller for the settings configuration window.// If this method is not implemented, no Settings option is provided.- (NSWindowController *)configurationWindowController;@end

发布一个基础类Plug-in接口

如果你想提供一个功能给所有的Plug-in可以发布一个基础类给所有的Plug-in去继承,如下例子:
声明:

#import <Cocoa/Cocoa.h>@interface MyAppEmbeddingView : NSView{@private    NSURL *_URL;    void *_reserved1;    void *_reserved2;    void *_reserved3;}- (id)initWithFrame:(NSRect)frameRect URL:(NSURL)URL;- (unsigned)interfaceVersion;- (NSURL *)URL;- (void)setURL:(NSURL *)URL;@end

实现:

#import "MyAppEmbeddingView.h"@implementation MyAppEmbeddingView- (id)initWithFrame:(NSRect)frameRect URL:(NSURL)URL{    self = [self initWithFrame:frameRect];    [self setURL:URL];    return self}- (unsigned)interfaceVersion{    return 0;}- (void)drawRect:(NSRect)rect{    NSEraseRect(rect);}- (NSURL *)URL{    return _URL;}- (void)setURL:(NSURL *)URL{    [URL retain];    [_URL release];    _URL = URL;}@end

加载Plug-in

加载插件的步骤:

  1. 在标准位置找到插件
  2. 加载每个插件的可执行代码
  3. 通过插件接口验证插件
  4. 实例化插件

验证Plug-in

如果是正式协议插件,需要检查实现该协议的类有没有都实现该协议的方法即可,代码如下:

- (BOOL)plugInClassIsValid:(Class)plugInClass{    if([plugInClass        conformsToProtocol:@protocol(MyGreatImageAppBitmapFiltering)])    {        if([plugInClass instancesRespondToSelector:                        @selector(interfaceVersion)] &&           [plugInClass instancesRespondToSelector:                        @selector(menuItemString)] &&           [plugInClass instancesRespondToSelector:                        @selector(filteredImageRep)] &&           [plugInClass instancesRespondToSelector:                        @selector(configurationWindowController])        {            return YES;        }    }    return NO;}

对于非正式协议更简单,只需要检查必须的方法即可,不用检查可选方法,代码如下:

- (BOOL)plugInClassIsValid:(Class)plugInClass{    if([plugInClass instancesRespondToSelector:                    @selector(interfaceVersion)] &&       [plugInClass instancesRespondToSelector:                    @selector(filteredImageRep)])    {        return YES;    }    return NO;}

继承基础类的检查只需要判断实现类的父类即可,代码如下:

- (BOOL)plugInClassIsValid:(Class)plugInClass{    if([plugInClass isSubclassOfClass:[MyAppEmbeddingView class]])    {        return YES;    }    return NO;}

加载Plug-in

NSString *ext = @"plugin";NSString *appSupportSubpath = @"Application Support/KillerApp/PlugIns";// ...- (void)loadAllPlugins{    NSMutableArray *instances;    NSMutableArray *bundlePaths;    NSEnumerator *pathEnum;    NSString *currPath;    NSBundle *currBundle;    Class currPrincipalClass;    id currInstance;    bundlePaths = [NSMutableArray array];    if(!instances)    {        instances = [[NSMutableArray alloc] init];    }    [bundlePaths addObjectsFromArray:[self allBundles]];    pathEnum = [bundlePaths objectEnumerator];    while(currPath = [pathEnum nextObject])    {        currBundle = [NSBundle bundleWithPath:currPath];        if(currBundle)        {            currPrincipalClass = [currBundle principalClass];            if(currPrincipalClass &&               [self plugInClassIsValid:currPrincipalClass])  // Validation            {                currInstance = [[currPrincipalClass alloc] init];                if(currInstance)                {                    [instances addObject:[currInstance autorelease]];                }            }        }    }}- (NSMutableArray *)allBundles{    NSArray *librarySearchPaths;    NSEnumerator *searchPathEnum;    NSString *currPath;    NSMutableArray *bundleSearchPaths = [NSMutableArray array];    NSMutableArray *allBundles = [NSMutableArray array];    librarySearchPaths = NSSearchPathForDirectoriesInDomains(        NSLibraryDirectory, NSAllDomainsMask - NSSystemDomainMask, YES);    searchPathEnum = [librarySearchPaths objectEnumerator];    while(currPath = [searchPathEnum nextObject])    {        [bundleSearchPaths addObject:            [currPath stringByAppendingPathComponent:appSupportSubpath]];    }    [bundleSearchPaths addObject:        [[NSBundle mainBundle] builtInPlugInsPath]];    searchPathEnum = [bundleSearchPaths objectEnumerator];    while(currPath = [searchPathEnum nextObject])    {        NSDirectoryEnumerator *bundleEnum;        NSString *currBundlePath;        bundleEnum = [[NSFileManager defaultManager]            enumeratorAtPath:currPath];        if(bundleEnum)        {            while(currBundlePath = [bundleEnum nextObject])            {                if([[currBundlePath pathExtension] isEqualToString:ext])                {                 [allBundles addObject:[currPath                           stringByAppendingPathComponent:currBundlePath]];                }            }        }    }    return allBundles;}
0 0
原创粉丝点击