티스토리 뷰

여기서 제목과 본문에 칭하는 '포함'은 프레임웍이나 라이브러리를 포함하는
php의 include() 나 c의 #import 등과 같은것입니다.

Sencha Touch 2에서는 application 내부나 클래스 안에서의 두가지 주요한 포함법이 가능하다. 앱에서 포함을 선언 하는  몇가지 방법을 알아봅시다.

Application 포함

MVC 프로그램 제작시, Ext.application에 모델, 뷰, 컨트롤러, 스토어와 프로파일 선언이 간편하다. 사례를 보죠:

Ext.application({
    name: 'MyApp',

    views: ['Login'],
    models: ['User'],
    controllers: ['Users'],
    stores: ['Products'],
    profiles: ['Phone', 'Tablet']
});

위 다섯 환경설정은 앱에 있는 models, views, controllers, stores, profiles 파일들을 불러오는 방법입니다. 이것들은 다음의 파일들을 자동으로 불러옵니다:

  • app/view/Login.js
  • app/model/User.js
  • app/controller/Users.js
  • app/store/Products.js
  • app/profile/Phone.js
  • app/profile/Tablet.js

위 예는 아래 같이 정의하는것과 같습니다:

Ext.require([
    'MyApp.view.Login',
    'MyApp.model.User',
    'MyApp.controller.Users',
    'MyApp.store.Products',
    'MyApp.profile.Phone',
    'MyApp.profile.Tablet'
]);

클래스 추가시, 이 설정들은 매번 전체 클래스명을 기술해야 하는 수고를 줄여줍니다. 환경설정들은 파일을 로딩하는것 뿐만이 아니라 그동안 다음과 같은 동작을 합니다:

  • profiles - 성되어야 한다면 각 프로파일과 결정을 인스턴스화. 그렇다면, 프로파일 자신의 의존 또한 로딩됨.
  • controllers - 로딩 후 각 컨트롤러 인스턴스화.
  • stores - 각 스토어 인스턴스화, 특별하지 않다면 기본 스토어 ID 부여됨.

이것의 의미는 MVC 편의의 모든것이 제공된다는 것입니다, 어플리케이션 포함 정의시 이런 환경설정 옵션을 고려만하면 됩니다.

프로파일-특정 포함

기 프로파일 사용시, chances are it means you have some classes that are used only on certain devices. 예를들어, 태블릿 버젼 앱에서는 폰버젼보다 많은 기능이 포함되어 있을것인데, 더 많은 클래스들을 불러야된다는것이겠죠. 추가 포함은 각각의 프로파일에 포함할 수 있습니다:

Ext.define('MyApp.profile.Tablet', {
    extend: 'Ext.app.Profile',

    config: {
        views: ['SpecialView'],
        controllers: ['Main'],
        models: ['MyApp.model.SuperUser']
    },

    isActive: function() {
        return Ext.os.is.Tablet;
    }
});

Now what's going to happen here is that the dependencies specified in each Profile are going to be loaded regardless of whether or not the Profile is active. The difference is, even though they're loaded, the Application knows not to do the additional processing like instantiating profile-specific Controllers if the profile is not active.

This probably sounds counter-intuitive - why download classes that aren't going to be used? The reason we do this is to produce a universal production build that can be deployed to any device, detect which profile it should use and then boot the app. The alternative is to create custom builds for each profile, craft a micro-loader than can detect which profile a device should activate and then download the code for that profile.

While the universal build approach does mean you're downloading code you don't need on every device, for the vast majority of apps this amounts to so little additional size it's difficult to detect the difference. For very large apps the difference will become more noticeable so it's possible we'll revisit this subject after 2.0.

포함 나열

For larger apps it's common to split the models, views and controllers into subfolders so keep the project organized. This is especially true of views - it's not unheard of for large apps to have over a hundred separate view classes so organizing them into folders can make maintenance much simpler.

하위폴더 포함은 단지 폴더에 점(".")을 붙이면 됩니다:

Ext.application({
    name: 'MyApp',

    controllers: ['Users', 'nested.MyController'],
    views: ['products.Show', 'products.Edit', 'user.Login']
});

위에서는 아래의 5개가 불려집니다:

  • app/controller/Users.js
  • app/controller/nested/MyController.js
  • app/view/products/Show.js
  • app/view/products/Edit.js
  • app/view/user/Login.js

Note that we can mix and match within each configuration here - for each model, view, controller, profile or store you can specify either just the final part of the class name (if you follow the directory conventions), or the full class name.

외부 포함

We can specify application dependencies from outside our application by fully-qualifying the classes we want to load. A common use case for this is sharing authentication logic between multiple applications. Perhaps you have several apps that login via a common user database and you want to share that code between them. An easy way to do this is to create a folder alongside your app folder and then add its contents as dependencies for your app.

예를들어, 공용 로그인 코딩시 로그인 컨트롤러, 사용자 모델, 로그인 폼 뷰. 이런것들 모두 우리의 어플리케이션에 있어야 합니다:

Ext.Loader.setPath({
    'Auth': 'Auth'
});

Ext.application({
    views: ['Auth.view.LoginForm', 'Welcome'],
    controllers: ['Auth.controller.Sessions', 'Main'],
    models: ['Auth.model.User']
});

위 코드는 다음의 파일들을 불러옵니다:

  • Auth/view/LoginForm.js
  • Auth/controller/Sessions.js
  • Auth/model/User.js
  • app/view/Welcome.js
  • app/controller/Main.js

처음 3개는 외부로부터 불려지며, 마지막 둘은 내부에서 부릅니다. Note how we can still mix and match application files and external dependency files.

이 파일들을 어디서 찾을 수 있는지 Loader에게 알려주면 된다는것을 알아둡시다, 위에서 보면 Ext.Loader.setPath 호출로 가능하죠. In this case we're telling the Loader to find any class starting with the 'Auth' namespace inside our 'Auth' folder. This means we can drop our common Auth code into our application alongside the app folder and the framework will be able to figure out how to load everything.

각각의 포함이 속하는 위치

각 포함 선언을 어디에 하는지 정할때의 기본 규칙은 자신이 포함된 클래스를 완벽히 지켜야 합니다. 뷰면 뷰 클래스에 선언하라는 것입니다. 예를들어, 몇몇 다른 뷰를 포함한 뷰가 있을때, 이런 종속을 application이 아닌 뷰 클래스 안에서 선언해줘야 합니다:

Ext.define('MyApp.view.Main', {
    extend: 'Ext.Container',

    requires: [
        'MyApp.view.Navigation',
        'MyApp.view.MainList'
    ],

    config: {
        items: [
            {
                xtype: 'navigation'
            },
            {
                xtype: 'mainlist'
            }
        ]
    }
});

app.js 에서는:

Ext.application({
    views: ['Main']
});

위와같이 하는 이유는 app.js 를 깨끗하게 지켜주고 MyApp.view.Main 요구를 확실히 가능하게 하고 이미 모든 포함이 충족되었음을 알게 하기 때문입니다. 다른 방법은 app.js 에 다음과 같이 모든 뷰 목록을 나열하는 것입니다:

//이것은 좋지 않음
Ext.application({
    views: ['Main', 'Navigation', 'MainList']
});

A simple way of thinking about this is that app.js just contains top-level views. If you use Ext.create('MyApp.view.SomeView') inside your app, that view can be considered top-level. If a view is only ever constructed as a sub-view of another view (as with MyApp.view.Navigation and MyApp.view.MainList above), it doesn't belong in app.js.

1.x 이후 변경

Sencha Touch 1에서는, 의존성은 Ext.application 호출에서 컨트롤러에서 특별히 열려있었죠. 이것이 몇가지 편의를 제공할 때, 시스템과 복사된 뷰, 모델과 스토어 컨트롤러의 진정한 구조를 감추기도 했습니다. 1.x에서 할수 있던것을 봅시다:


//1.x code, 사용중지됨 Ext.regController('SomeController', { views: ['Login'], models: ['User'], stores: ['Products'] });

This is exactly the same as defining the views, models and stores inside Ext.application, but also gave some convenience methods for accessing those classes inside your controller. 1.x generated two functions - getLoginView() 그리고 getUserModel() - and exposed a getStore()function that returned a reference to any of the Stores you defined in this Controller. In 2.x these functions no longer exist, but it's easy to use the alternatives.

다음 사례의 첫줄은 Sencha Touch 1.x, 이고 두번째 줄은 2.x 방식입니다:

//뷰 만들기 - 2.x 는 표준화된 Ext.create 사용
this.getLoginView().create();
Ext.create('MyApp.view.Login');

//모델 만들기 - 모델명만 기술하면 됨 (간결하면서 빠름)
this.getUserModel();
MyApp.model.User;

//Ext.getStore는 어떤 스토어든 접근 가능한데 비해 기존 this.getStore는
//컨트롤러 목록에 있는 스토어에만 접근 가능했다.
this.getStore('Products');
Ext.getStore('Products');

Removing these functions speeds up application launching because the framework no longer needs to generate one function for each model and view defined in each Controller. It also means that the conventions for MVC match the conventions for the rest of the framework, leading to a more predictable API.

[원문] http://docs.sencha.com/touch/2-0/#!/guide/mvc_dependencies

댓글