Jonathan Li

There are lots of helpful information available on internet, so just share some notes I found useful during application development, to contribute back to the community. Jonathan in Toronto

Sunday, June 23, 2013

cordova.js javascript logic

One of the things that makes cordova confuse is it uses the same name for both function parameter and variable.

When cordova.js is called, the outmost function first set the cordova version number and then declare two closure function variables: define and require.
And then it executes another inner function, which implements the define and require function, and modules variable exposed by define.moduleMap.
Up to now, the following variables have been defined inside function scope:
define
require
define.moduleMap
define.remove
When require function is called, it returns the module.exports, which is usually a constructor function to create the module instance. (71:   return modules[id].exports;)

Next, it call define method on cordova and other modules, which will put those modules in modules list. The factory function is not called yet.
define("cordova", function(require, exports, module)...);

define("cordova/argscheck", function(require, exports, module)
define("cordova/channel", function(require, exports, module) 
.....
Then it loads the cordova module with the following line:
window.cordova = require('cordova');
    function build(module) 
    factory:function(require, exports, module). In the factory method, require is the input parameter, container the define function. module is the input parameter represent the current module. exports is the output parameter containing the exported function for the module.
 
The cordova module factory function then load channel by requires it with following code
102: var channel = require('cordova/channel');

For channel:
Note the line 102, var channel = require('cordova/channel');  The var channel contains the exported       javascript object returned to channel.exports. The Channel defined in line
var Channel = function(type, sticky) {
is the prototype construtor for creating an individual channel object, which can handle a particular event
514: var utils = require('cordova/utils'),
After utils module is loaded, channel module register events with the following calls
722: channel.createSticky('onDOMContentLoaded');
725: channel.createSticky('onNativeReady');

107: after channel module is loaded,  cordova module can hookup document event with channel event
186: var cordova = { create the cordova object as exported javascript object
328: expose cordova module by: module.exports = cordova;

6255: (function (context) { call the context method on window object, it will require and load all modules, like contact, and file



 
Posted by Jonathan Li at 11:11 AM No comments:

Saturday, June 22, 2013

cordova ios native code logic

For cordova ios project created by cordova create command, the application and plugin starting up includes the following logic:
1.  AppDelegate
In didFinishLaunchingWithOptions, it initializes MainViewController, which is a subclass of CDVViewController. The init of CDVViewController will hook up cordova function with application.

2. CDVViewController
In CDVViewController, __init method, it first registers all application notification event, so that it can relay those event to javascript. Then it calls loadSettings, which will parse config.xml which defines the cordova behavior, including starting page and plugin definition.
The CDVViewController owns all plugins instance after the instances are created. That is the plugin lives within CDVViewController's scope and lifetime. However, it is possible, the same webview loads multiple html js app, in that case, the plugin's state in native code will not be reset automatically when new page loads. For this reason, CDVPlugin interface defines a method onReset to clean up the plugin state from js page to page. This method should be implemented by each plugin.

The CDViewController has an important method createGapView, which is called in viewDidLoad method. This method creates UIWebView control, and also sets CDVViewDelegate to the UIWebView instance, to handle the page event. The createGapView method also hooks up with javascript request using CDVURLProtocol (a sub class of NSUrlProtocol).  When a javascript method is called,

3. plugin
Usually, plugin will not create its instance until its method is called the first time. But it can also create its instance during ApplicationDidFinishingWithOption by setting onLoad attribute in config.xml. If so,  the PluginInitialize method can be implemented to register the application events including openUrl, etc. Some basic event it registered by its base class CDVPlugin interface, so do not register those event again.
The plugin method is alway called from the main thread.




Posted by Jonathan Li at 8:24 PM No comments:

Friday, June 21, 2013

xcode iphone project interface name conflict

When an ios xcode application uses more than one static libraries, if the libraries include the same interface with their own implementation, then when application creates the interface instance, a conflict will happen, as it cannot decide which library's implementation should be used.
However, the strange thing is xcode does not give a warning or error when building the application when this happens. The error will happen in runtime, it seems xcode just pick one of the implementation to continue.
The correct way to handle it is create a base library that includes the shared common source interface, and implementation, and then reference it from all other libraries and the application.
Posted by Jonathan Li at 11:54 AM No comments:

Monday, June 17, 2013

Understanding "this" and its scope in javascript


This in javascript code is a confusing concept, and needs few rules to clarify it:
1. only use this in function definition, this does not work in object initialization
var obj = {
    a: 5,
    b: this.a + 1 
}
alert(obj.b);//b is undefined
2. even if a method is defined as a property of an object, when the method is called, the this may point to a different object, this different from C++/C# or java.
function test(){
var a ={
 answer : "a",
 func : function(){
  alert(this ==a);
 }
};
a.func();  //this inside func is a
var b = a.func;
b.call(b); //this inside func is b
}

3. Within the function body, if the function is invoked as myfunc();, then the global window object is used as this.
var a = {a:"parent"};
a.func =function(){
alert(this);
}
a.func(); //this is a inside func
var b = a.func;
b(); //this is window inside func, even if it refers a property function of object a

4. if the method is invoked with a dot as myobj.mymMethod();, then the myobj is used as this, except for constructor invocation described in the next two item (item 5 and 6)

5. when function is invoked as constructor with "new", such as myfunct() or new myobject.myfunc(), then this is the new object created for running the function. Basically, it first create a new object and set the new object as this for invoking the function. It also explains the difference between two ways to call a method:
funcA();
with
new funcA() or new objA.funcA();
as the this points to different objects in the two cases.

6. if the method or function is invoked as myMethod.call(yourObj, ...) or myObject.myMethod.call(yourObj) or myMethod.apply(yourobj) or myObject.myMethod.app(yourObj), then the yourObj is used as this, even if myObject is used to invoke the method.

7. Note that although inner function can access all variables defined in the parent function or object, it may not access the variables defined as this.parentvariable, as "this" for inner function may be different from "this" in the parent function.

8. It is obvious to see the difference on html element between
onclick=externaljsfunction;
and
onclick="externaljsfunction();"

when onclick is called, its "this" is the current html element, so in first case, externaljsfunction has the html element as its this. In second case, when externaljsfunction is called, this is set to window, unless change it to onclick="externaljsfunction.call(this)";

9. what is use of the below code
self = this;
The only purpose of this code is keeping track the this object so as to use it later by inner function. As when inner function or callback method is called, this object may be set to any value, the only way to get the parent function's this is assigning it to a variable in parent function, and then get it back using closure

var user = {
    tournament:"The Masters",
    data      :[
         {name:"T. Woods", age:37},
         {name:"P. Mickelson", age:43}
    ],

    clickHandler:function (event) {
    // set "this" to theUserObj variable, so we can use it later
    var self = this;
    this.data.forEach (function (person) {
// this now points to window object, but we can use theUserObj.tournament
console.log (person.name + " is playing at " + self.tournament);
      });
    }
};
user.clickHandler();

10.  bind this with setTimeout
setTimeout can be used to wrap synchronous call to asynchronous call. By default, when a method is called through setTimeout(), the "this" keyword will be set to the window object. In order to keep the original this object when setTimeout is called, you can explicitly bind the original this to the callback function
var a={
name:"myname",
mycall:function(){
console.log(this.name);
},
myasyncCall:function(){
setTimeout(this.mycall.bind(this), 0);
},
myasyncCallWrong:function(){
setTimeout(this.mycall, 0);
},
};
a.mycall();
a.myasyncCallWrong();  //this is window when mycall is invoked
a.myasyncCall(); //this is object a

11.sample code to use constructor parameter
function Person(gender) {
  if (arguments.length == 0) return; // do nothing if no paras for subclass constructor
  this.gender = gender;
}

function Student(gender) {
  Person.apply(this, arguments); //apply paras to parent constructor
}
Student.prototype = new Person(); // make Student inherit from a Person object
Student.prototype.constructor = Student; // fix constructor property

var foo = new Student('male');
foo.gender;             // "male"
foo instanceof Student; // true
foo instanceof Person;  // true

12. Similarly rule also applies to the variable, if it is referred as myObject.myVariable, then myVariable is searched from myObject's properties. if it is referred as myVariable directly, then it will search the global object's properties (i.e the window object)

13. Difference between method declared as arrow expression
When method is defined using arrow expression, this is hardcoded to bind to the this when the method is created, and ignores the this set to it at runtime. 
class myComponent {
  onTempTest2() {
    const obj = {
      name: 'Jonathan',
      func(){
        console.log(this);
      },
      myfunc : () => {
        console.log(this); //this is hard coded to this instance when the method is defined
      }
    };
    obj.func(); //inside func method invocation, this is obj
    obj.myfunc(); //inside myfunc method invocation, this is instance of myComponent

    const t = obj.func;
    const t2 = obj.myfunc;

    t(); // inside func invocation, this is undefined
    t2(); // inside myfunc invocation, this is instance of myComponent


    t.call(window); //this is window object
    t2.call(window); //this is instance of myComponent
    
//current this myComponent instance
t.call(this); // this is instance of myComponent, referred from parameter
    t2.call(this); //this is instance of myComponent referred from arrow function context

setTimeout(() => { t(); //inside func invocation, this is undefined }, 100); setTimeout(() => { t2(); //inside myfunc invocation, this is myComponent }, 100);
}

Posted by Jonathan Li at 6:57 AM No comments:

Monday, May 27, 2013

What Array.prototype.slice.call(arguments) does in javascript

Why using Array.prototype.slice.call(arguments) in javascript? Basically it is used to convert multiple arguments into a single argument in array type, as the some js method may only accept one argument instead of several arguments.

for example:
func2(arg){
  console.log(arg);
}

func1(arg1, arg2, arg3)
{
   arg = Array.prototype.slice.call(arguments);
   func2(arg);
}

It can be understood as the following conversion:
    Array.prototype.slice.call(arguments);
==  Array.prototype.slice(arguments[1], arguments[2], arguments[3], ...)
==  [ arguments[1], arguments[2], arguments[3], ... ]
Posted by Jonathan Li at 8:38 PM No comments:

Monday, May 20, 2013

About XCode project, target, build settings and schema

A target uses build settings to build the output. Targets in a project inherits build settings if it does not specify a build setting. Project have debug or release build settings. Schema is a selection of specifying which target  and which build configuration to build, and on which platform (device or simulator) to run. So schema is a configuration for user operation, it is not a project settings.

A project defines default build settings for all the targets in the project (each target can also specify its own build settings, which override the project build settings). In project-level build configurations. You can specify more than one build configuration for a project; for example, you might have debug and release build settings for a project.

A target inherits the project build settings, but you can override any of the project settings by specifying different settings at the target level. There can be only one active target at a time; the Xcode scheme specifies the active target. Each target can specify its own source file to build.


You can specify build settings at the project or target level. Each project-level build setting applies to all targets in the project unless explicitly overridden by the build settings for a specific target.
Each target organizes the source files needed to build one product. A build configuration specifies a set of build settings used to build a target's product in a particular way. For example, it is common to have separate build configurations for debug and release builds of a product.

An Xcode scheme defines a collection of targets to build, a configuration to use when building, and a collection of tests to execute.
You use Xcode schemes to specify which target, build configuration, and executable configuration is active at a given time.



Posted by Jonathan Li at 8:47 AM No comments:

Sunday, May 19, 2013

Fix the cordova project compile error of unable to find

After creating a cordova project by using the create script provided by cordova download, when compile the project, an error may happen for "unable to find <Cordova/CDVViewController.h>.

If you just search the project, you will not be able to find the mentioned folder or file. That is expected, as xCode refers the dependency path based on application's built output's folder structure, not project's folder structure as visual studio. 

A easy way to fix the issue is doing a build first, and then open the build output folder in finder, 
For example, your XCode project may have set the preference\location\derived data\advanced...\build location to "legacy" instead of "unique", as that would make the main project fails to find the dependent build output, as cordovamay define its own ouput path and the application . Change it to unique should work. You can find the folder and file in the cordovalib' build output.
Posted by Jonathan Li at 9:25 AM No comments:
Newer Posts Older Posts Home
View mobile version
Subscribe to: Posts (Atom)

Followers

About Me

Jonathan Li
View my complete profile

Blog Archive

  • ▼  2025 (3)
    • ▼  March (1)
      • Javascript function to log the current method name...
    • ►  February (2)
  • ►  2024 (2)
    • ►  March (2)
  • ►  2023 (1)
    • ►  June (1)
  • ►  2022 (7)
    • ►  August (1)
    • ►  July (1)
    • ►  June (2)
    • ►  January (3)
  • ►  2021 (15)
    • ►  December (4)
    • ►  November (2)
    • ►  October (2)
    • ►  September (4)
    • ►  July (1)
    • ►  January (2)
  • ►  2020 (23)
    • ►  December (2)
    • ►  November (1)
    • ►  September (3)
    • ►  August (2)
    • ►  July (5)
    • ►  June (4)
    • ►  May (2)
    • ►  April (1)
    • ►  March (1)
    • ►  February (1)
    • ►  January (1)
  • ►  2019 (38)
    • ►  November (4)
    • ►  October (5)
    • ►  September (1)
    • ►  August (9)
    • ►  July (4)
    • ►  June (3)
    • ►  May (6)
    • ►  April (3)
    • ►  March (1)
    • ►  January (2)
  • ►  2018 (42)
    • ►  December (2)
    • ►  November (7)
    • ►  October (1)
    • ►  September (3)
    • ►  August (3)
    • ►  July (2)
    • ►  May (5)
    • ►  April (5)
    • ►  March (5)
    • ►  February (4)
    • ►  January (5)
  • ►  2017 (40)
    • ►  December (3)
    • ►  November (5)
    • ►  September (2)
    • ►  August (1)
    • ►  July (5)
    • ►  June (4)
    • ►  May (3)
    • ►  April (1)
    • ►  March (9)
    • ►  February (3)
    • ►  January (4)
  • ►  2016 (27)
    • ►  November (5)
    • ►  October (2)
    • ►  September (5)
    • ►  August (1)
    • ►  April (4)
    • ►  March (4)
    • ►  February (5)
    • ►  January (1)
  • ►  2015 (35)
    • ►  November (3)
    • ►  October (4)
    • ►  September (6)
    • ►  August (3)
    • ►  July (2)
    • ►  June (3)
    • ►  May (6)
    • ►  April (2)
    • ►  March (2)
    • ►  January (4)
  • ►  2014 (45)
    • ►  December (2)
    • ►  November (5)
    • ►  October (5)
    • ►  September (7)
    • ►  August (4)
    • ►  July (4)
    • ►  May (5)
    • ►  April (6)
    • ►  March (1)
    • ►  February (2)
    • ►  January (4)
  • ►  2013 (43)
    • ►  December (10)
    • ►  November (7)
    • ►  October (3)
    • ►  September (4)
    • ►  July (5)
    • ►  June (4)
    • ►  May (5)
    • ►  April (2)
    • ►  March (2)
    • ►  February (1)
  • ►  2012 (16)
    • ►  November (3)
    • ►  October (5)
    • ►  September (1)
    • ►  July (2)
    • ►  May (2)
    • ►  April (1)
    • ►  March (1)
    • ►  February (1)
  • ►  2011 (34)
    • ►  November (3)
    • ►  October (2)
    • ►  September (2)
    • ►  June (2)
    • ►  May (1)
    • ►  April (4)
    • ►  March (9)
    • ►  February (9)
    • ►  January (2)
  • ►  2010 (12)
    • ►  December (7)
    • ►  November (4)
    • ►  June (1)
Simple theme. Theme images by gaffera. Powered by Blogger.