• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            羅朝輝(飄飄白云)

            關(guān)注嵌入式操作系統(tǒng),移動(dòng)平臺(tái),圖形開發(fā)。-->加微博 ^_^

              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              85 隨筆 :: 0 文章 :: 169 評(píng)論 :: 0 Trackbacks
            深入淺出 Cocoa 之 Plugin
            CC許可,轉(zhuǎn)載請(qǐng)注明出處

            在前文 深入淺出 Cocoa 之 Framework 中講解了 Framework,接下來(lái)講解 plugin。如果你對(duì) Framework 還不太熟悉的話,請(qǐng)閱讀那篇文中,在本例中使用到了 framework,并在本文中沒(méi)有詳細(xì)講述其創(chuàng)建和使用過(guò)程。

            本文代碼下載:點(diǎn)擊這里

            為什么要引入插件?
            我們知道編譯程序時(shí),會(huì)連接相關(guān) framework,通常我們所連接的框架是 Foundation 和 Application 框架。當(dāng)程序啟動(dòng)運(yùn)行時(shí),每個(gè)被連接到的 framework 都會(huì)被加載到該程序的 objc 運(yùn)行時(shí)環(huán)境中。如果我們想向正在運(yùn)行的程序加載新的 framework,那該怎么辦呢?答案之一就是使用 plugin 機(jī)制。cocoa 的 plugin 機(jī)制通常由 NSBundle 類來(lái)實(shí)現(xiàn),而實(shí)現(xiàn)動(dòng)態(tài)加載的功能由函數(shù) objc_addClass 來(lái)完成。一般我們無(wú)需與 objc_addClass 這個(gè)函數(shù)打交道,我們使用 NSBundle 來(lái)完成絕大部分與 plugin 相關(guān)的工作。

            plugin 機(jī)制能夠讓我們開發(fā)出高度模塊化,可定制以及可擴(kuò)展的應(yīng)用程序,并能夠讓第三方為該應(yīng)用程序添加新特性。想必很多人都熟悉 Eclipse,Eclipse 的 plugin 機(jī)制就非常方便與強(qiáng)大。

            NSBundle 簡(jiǎn)介
            束(bundle)是文件系統(tǒng)中的一個(gè)目錄結(jié)構(gòu),它將程序會(huì)使用到的資源打包在一起。這些資源可包括編譯好的代碼,nib文件,配置文件,圖像,聲音,本地化資源等等。束是 Mac OS X 的一個(gè)核心特性,應(yīng)用程序,F(xiàn)ramework,插件都是一個(gè)束,只是擴(kuò)展名各異,如應(yīng)用程序的擴(kuò)展名為 .app;Framework 的擴(kuò)展名是 .framework;插件的擴(kuò)展名默認(rèn)為 .bundle。

            一個(gè) plugin 就是一個(gè) bundle(束),xcode 默認(rèn)以 .bundle 為擴(kuò)展名。通常我們使用我們自己定義的擴(kuò)展名,以便與系統(tǒng)或其他人編寫的 plugin 區(qū)分開來(lái)。我們通過(guò) NSBundle 來(lái)載入 bundle,并把其中經(jīng)過(guò)編譯的類注冊(cè)到 objc 運(yùn)行時(shí)中,然后我們就能在程序中使用這些類了;我們也可以使用 bundle 中的所有資源。

            plugin 構(gòu)架
            我們可以通過(guò)多種途徑來(lái)實(shí)現(xiàn)一個(gè) plugin:
            1,定義一個(gè) objc protocol,讓 plugin 遵守該 protocol;
            2,定義一個(gè)基類,讓 plugin 繼承該基類;
            3,定義一個(gè) C 回調(diào)函數(shù)接口,讓 plugin 實(shí)現(xiàn)改回調(diào)函數(shù);
            4,使用 CFPlugIn 來(lái)創(chuàng)建 plugin 接口;
            在今天的例子中,使用的是第二種情況,這種情況稍稍復(fù)雜一些,我們需創(chuàng)建一個(gè) framework 供宿主程序(使用插件的程序)和 plugin 使用,該 framework 的主要職責(zé)是提供基類接口。

            plugin 的存放目錄
            通常 plugin 總是存放在以下三個(gè)位置:
            1,應(yīng)用程序名.app/Contents/Plug-ins   這是程序的開發(fā)者存放隨產(chǎn)品發(fā)布的插件的地方。 
            2,~/Library/Application Support/應(yīng)用程序名/Plug-ins  用戶存放個(gè)人插件的地方。
            3,/Library/Application Support/應(yīng)用程序名/Plug-ins   系統(tǒng)中供全部用戶使用的插件。
             
            在今天的例子中,使用的是第一種情況,即將插件存放在應(yīng)用程序包中。

            創(chuàng)建宿主程序
            我們來(lái)創(chuàng)建一個(gè)名為 PluginDemo 的 cocoa application,該程序含有一個(gè)顯示已安裝 plugin 的 popup button 以及一個(gè)執(zhí)行選中 plugin 的 button。


            創(chuàng)建 framework
            1,創(chuàng)建名為 PluginFramework 的 framework,向其中添加 plugin 基類:AbstractPlugin。如果你忘記怎樣創(chuàng)建和使用 framework,請(qǐng)參看前文:深入淺出 Cocoa 之 Framework


            AbstractPlugin 類僅僅提供兩個(gè)接口:name 用來(lái)標(biāo)識(shí) plugin,run 用來(lái)供宿主程序運(yùn)行插件。
            - (NSString *)name;
            - (IBAction)run:(id)sender;

            2,在 PluginDemo 中連接和使用該 framework 來(lái)運(yùn)行插件。如果你忘記怎樣連接和使用 framework,請(qǐng)參看前文:深入淺出 Cocoa 之 Framework。我們?cè)诎粹o響應(yīng)函數(shù)中,運(yùn)行選中的插件。
            - (IBAction)runPlugin:(id)sender
            {
                AbstractPlugin 
            *plugin = [[pluginsController selectedObjects] lastObject];
                
            if (!plugin)
                    
            return;

                [plugin run:sender];
            }

            創(chuàng)建 plugin
            1,創(chuàng)建 plugin;


            2,連接 PluginFramework;如果你忘記怎樣連接和使用 framework,請(qǐng)參看前文:深入淺出 Cocoa 之 Framework

            3,創(chuàng)建 UI 界面;


            4,創(chuàng)建繼承自基類的 plugin 子類:PluginOne;

            PluginOne 類繼承自 AbstractPlugin,它僅僅是顯示和隱藏一個(gè) window,其實(shí)現(xiàn)如下:
            #import "PluginOne.h"

            @implementation PluginOne

            @synthesize mainWindow;

            - (id)init
            {
                self 
            = [super init];
                
            if (self) {
                    
            // Initialization code here.
                    
                    [NSBundle loadNibNamed:
            @"PluginOneMainWindow" owner:self];
                }
                
                
            return self;
            }

            - (void)dealloc
            {
                mainWindow 
            = nil;

                [super dealloc];
            }

            - (NSString *)name;
            {
                
            return @"Plugin One";
            }

            - (IBAction)run:(id)sender;
            {
                [mainWindow center];
                [mainWindow makeKeyAndOrderFront:sender];
            }

            - (IBAction)closeWindow:(id)sender;
            {
                [mainWindow orderOut:sender];
            }

            @end

            5,plugin 設(shè)置
            下面我們來(lái)對(duì) plugin 進(jìn)行設(shè)置,我們可以設(shè)置其 Principal class,Wrapper Extension(擴(kuò)展名)。


            使用 plugin
            1,宿主程序設(shè)置
            前面說(shuō)了,在這個(gè)例子中,我們打算將插件隨宿主程序一起發(fā)布,所以其存放位置就在宿主應(yīng)用程序包中。因此我們需要在宿主程序種添加一個(gè) Add Copy Files 的 build phase,如下所示:


            2,載入plugin
            在正式的應(yīng)用中,我們應(yīng)該在前面提到的三個(gè)目錄下去查找所有 plugin,因?yàn)檫@三個(gè)目錄都是 Cocoa 所推薦的 plugin 目錄。在這個(gè)例子中,演示的是隨宿主應(yīng)用程序一起發(fā)布的程序,所以我只掃描了應(yīng)用程序包中的目錄。
            - (NSArray *)loadPlugins
            {
                NSBundle 
            *main = [NSBundle mainBundle];
                NSArray 
            *allPlugins = [main pathsForResourcesOfType:@"bundle" inDirectory:@"../PlugIns"];
                
                NSMutableArray 
            *availablePlugins = [[[NSMutableArray alloc] init] autorelease];
                
                id plugin 
            = nil;
                NSBundle 
            *pluginBundle = nil;
                
                
            for (NSString *path in allPlugins) {
                    pluginBundle 
            = [NSBundle bundleWithPath:path];
                    [pluginBundle load];
                    
                    Class principalClass 
            = [pluginBundle principalClass];
                    
            if (![principalClass isSubclassOfClass:[AbstractPlugin class]]) {
                        
            continue;
                    }
                    
                    plugin 
            = [[principalClass alloc] init];
                    
                    
            if ([plugin respondsToSelector:@selector(run:)])
                    {
                        [availablePlugins addObject:plugin];
                        NSLog(
            @" >> loading plugin %@ from %@", [plugin name], path);
                    }
                    
                    [plugin release];
                    plugin 
            = nil;
                    pluginBundle 
            = nil;
                }

                
            return availablePlugins;
            }

            該函數(shù)在 init 中被調(diào)用:
            - (id)init
            {
                self 
            = [super init];
                
            if (self) {
                    plugins 
            = [[self loadPlugins] retain];
                    
            //plugins = [[self loadAllPlugins] retain];
                }
                
                
            return self;
            }

            下面提供一個(gè)函數(shù)掃描前面提到的三個(gè)目錄,你可以用這個(gè)函數(shù)提到上面代碼中對(duì) loadPlugins 的調(diào)用:
            - (NSArray *)loadAllPlugins
            {
                NSString 
            *appName       = @"PluginOne/Plugins";
                NSString 
            *appSupport    = @"Library/Application Support";
                appSupport              
            = [appSupport stringByAppendingPathComponent:appName];

                NSString 
            *appPath       = [[NSBundle mainBundle] builtInPlugInsPath];
                NSString 
            *userPath      = [NSHomeDirectory() stringByAppendingPathComponent:appSupport];
                NSString 
            *sysPath       = [@"/" stringByAppendingPathComponent:appSupport];
                
                NSArray
            * paths = [NSArray arrayWithObjects:appPath, userPath, sysPath, nil];
                
                NSMutableArray 
            * availablePlugins = [[[NSMutableArray alloc] init] autorelease];
                
            for (NSString * path in paths)
                {
                    NSLog(
            @" >> Search in directory: %@", path);

                    NSArray 
            *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL];
                    
            for (NSString *fileName in contents)
                    {
                        
            if ( [[fileName pathExtension] isEqualToString:@"plugin"|| [[fileName pathExtension] isEqualToString:@"bundle"])
                        {
                            NSString 
            *fullPath = [path stringByAppendingPathComponent:fileName];
                            NSBundle 
            *pluginBundle = [NSBundle bundleWithPath:fullPath];
                            
            if (pluginBundle && [pluginBundle load])
                            {
                                Class principalClass 
            = [pluginBundle principalClass];
                                
            if (![principalClass isSubclassOfClass:[AbstractPlugin class]]) {
                                    
            continue;
                                }
                                
                                id plugin 
            = [[principalClass alloc] init];
                                
                                
            if ([plugin respondsToSelector:@selector(run:)])
                                {
                                    [availablePlugins addObject:plugin];
                                    NSLog(
            @" >> loading plugin %@ from %@", [plugin name], path);
                                }
                                
                                [plugin release];
                                plugin 
            = nil;
                            }
                        }
                    }
                }
                
                
            return availablePlugins;
            }

            運(yùn)行結(jié)果
            顯示 plugin 列表的 popupbutton 的內(nèi)容被綁定到該 plugins 數(shù)組,所以程序啟動(dòng)之后,就能顯示 plugin 的列表。運(yùn)行結(jié)果如下:


            點(diǎn)擊運(yùn)行之后,就能顯示出插件主界面:


            Reference
            Code Loading Programming Topics provides information about writing plug-ins using the Objective-C language.
            Bundle Programming Guide provides an overview to bundles, including their purpose, types, structure, and the API for accessing bundle resources.

            posted on 2011-10-28 14:44 羅朝輝 閱讀(2552) 評(píng)論(0)  編輯 收藏 引用 所屬分類: Cocoa 開發(fā)
            色综合久久久久综合体桃花网| 久久精品国产亚洲av瑜伽| 色综合久久无码五十路人妻| 午夜久久久久久禁播电影| 久久国产精品-久久精品| 久久人妻少妇嫩草AV无码蜜桃| 中文字幕热久久久久久久| 欧美va久久久噜噜噜久久| 久久99国产精品成人欧美| 久久久无码人妻精品无码| 一级a性色生活片久久无少妇一级婬片免费放 | 亚洲伊人久久成综合人影院 | 一本一本久久a久久综合精品蜜桃| 久久久久久久综合日本亚洲| 亚洲日韩欧美一区久久久久我 | 免费一级欧美大片久久网| 精品一二三区久久aaa片| 久久精品国产99久久丝袜| www.久久热.com| 久久丫精品国产亚洲av不卡| 亚洲国产视频久久| 久久99精品免费一区二区| 久久精品国产秦先生| 久久久精品2019免费观看| 伊人久久大香线蕉av不变影院| 亚洲va中文字幕无码久久| 久久久久亚洲国产| 亚洲综合久久夜AV | 看全色黄大色大片免费久久久| 久久强奷乱码老熟女网站| 久久久久久狠狠丁香| 青青热久久综合网伊人| 久久免费精品视频| 久久精品国产99国产精品澳门| 久久播电影网| 老司机午夜网站国内精品久久久久久久久| 大香网伊人久久综合网2020| 久久―日本道色综合久久| 99久久99久久| 激情五月综合综合久久69| 久久久91人妻无码精品蜜桃HD|