iOS owner pattern changed to use WeakRef in order to prevent memory leaks.

Optimized list-view-tests.
Added time per test.
This commit is contained in:
hshristov
2015-10-22 10:26:59 +03:00
parent 9c0ac9e471
commit f72d79e65a
22 changed files with 863 additions and 791 deletions

View File

@@ -51,7 +51,7 @@ export class ActionBar extends common.ActionBar {
// Set back button text
if (previousController) {
if (this.navigationButton) {
var tapHandler = TapBarItemHandlerImpl.new().initWithOwner(this.navigationButton);
var tapHandler = TapBarItemHandlerImpl.initWithOwner(new WeakRef(this.navigationButton));
var barButtonItem = UIBarButtonItem.alloc().initWithTitleStyleTargetAction(this.navigationButton.text + "", UIBarButtonItemStyle.UIBarButtonItemStylePlain, tapHandler, "tap");
previousController.navigationItem.backBarButtonItem = barButtonItem;
}
@@ -112,7 +112,7 @@ export class ActionBar extends common.ActionBar {
}
private createBarButtonItem(item: dts.ActionItem): UIBarButtonItem {
var tapHandler = TapBarItemHandlerImpl.new().initWithOwner(item);
var tapHandler = TapBarItemHandlerImpl.initWithOwner(new WeakRef(item));
// associate handler with menuItem or it will get collected by JSC.
(<any>item).handler = tapHandler;
@@ -129,7 +129,7 @@ export class ActionBar extends common.ActionBar {
return barButtonItem;
}
public _onTitlePropertyChanged() {
if (!this.page) {
return;
@@ -141,7 +141,7 @@ export class ActionBar extends common.ActionBar {
private _navigationBarHeight: number = 0;
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number) {
let width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
let widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);
@@ -186,19 +186,19 @@ export class ActionBar extends common.ActionBar {
}
class TapBarItemHandlerImpl extends NSObject {
static new(): TapBarItemHandlerImpl {
return <TapBarItemHandlerImpl>super.new();
}
private _owner: WeakRef<dts.ActionItemBase>;
private _owner: dts.ActionItemBase;
public initWithOwner(owner: dts.ActionItemBase): TapBarItemHandlerImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<dts.ActionItemBase>): TapBarItemHandlerImpl {
let handler = <TapBarItemHandlerImpl>TapBarItemHandlerImpl.new();
handler._owner = owner;
return handler;
}
public tap(args) {
this._owner._raiseTap();
let owner = this._owner.get();
if (owner) {
owner._raiseTap();
}
}
public static ObjCExposedMethods = {

View File

@@ -2,19 +2,19 @@
import stateChanged = require("ui/core/control-state-change");
class TapHandlerImpl extends NSObject {
static new(): TapHandlerImpl {
return <TapHandlerImpl>super.new();
}
private _owner: WeakRef<Button>;
private _owner: Button;
public initWithOwner(owner: Button): TapHandlerImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<Button>): TapHandlerImpl {
let handler = <TapHandlerImpl>TapHandlerImpl.new();
handler._owner = owner;
return handler;
}
public tap(args) {
this._owner._emit(common.Button.tapEvent);
let owner = this._owner.get();
if (owner) {
owner._emit(common.Button.tapEvent);
}
}
public static ObjCExposedMethods = {
@@ -33,7 +33,7 @@ export class Button extends common.Button {
super();
this._ios = UIButton.buttonWithType(UIButtonType.UIButtonTypeSystem);
this._tapHandler = TapHandlerImpl.new().initWithOwner(this);
this._tapHandler = TapHandlerImpl.initWithOwner(new WeakRef(this));
this._ios.addTargetActionForControlEvents(this._tapHandler, "tap", UIControlEvents.UIControlEventTouchUpInside);
this._stateChangedHandler = new stateChanged.ControlStateChangeListener(this._ios, (s: string) => {

View File

@@ -71,7 +71,7 @@ export class DatePicker extends common.DatePicker {
this._ios = new UIDatePicker();
this._ios.datePickerMode = UIDatePickerMode.UIDatePickerModeDate;
this._changeHandler = UIDatePickerChangeHandlerImpl.new().initWithOwner(this);
this._changeHandler = UIDatePickerChangeHandlerImpl.initWithOwner(new WeakRef(this));
this._ios.addTargetActionForControlEvents(this._changeHandler, "valueChanged", UIControlEvents.UIControlEventValueChanged);
}
@@ -81,30 +81,33 @@ export class DatePicker extends common.DatePicker {
}
class UIDatePickerChangeHandlerImpl extends NSObject {
static new(): UIDatePickerChangeHandlerImpl {
return <UIDatePickerChangeHandlerImpl>super.new();
}
private _owner: DatePicker;
private _owner: WeakRef<DatePicker>;
public initWithOwner(owner: DatePicker): UIDatePickerChangeHandlerImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<DatePicker>): UIDatePickerChangeHandlerImpl {
let impl = <UIDatePickerChangeHandlerImpl>UIDatePickerChangeHandlerImpl.new();
impl._owner = owner;
return impl;
}
public valueChanged(sender: UIDatePicker) {
var comps = NSCalendar.currentCalendar().componentsFromDate(NSCalendarUnit.NSCalendarUnitYear | NSCalendarUnit.NSCalendarUnitMonth | NSCalendarUnit.NSCalendarUnitDay, sender.date);
if (comps.year !== this._owner.year) {
this._owner._onPropertyChangedFromNative(common.DatePicker.yearProperty, comps.year);
let owner = this._owner.get();
if (!owner) {
return;
}
if (comps.month !== this._owner.month) {
this._owner._onPropertyChangedFromNative(common.DatePicker.monthProperty, comps.month);
if (comps.year !== owner.year) {
owner._onPropertyChangedFromNative(common.DatePicker.yearProperty, comps.year);
}
if (comps.day !== this._owner.day) {
this._owner._onPropertyChangedFromNative(common.DatePicker.dayProperty, comps.day);
if (comps.month !== owner.month) {
owner._onPropertyChangedFromNative(common.DatePicker.monthProperty, comps.month);
}
if (comps.day !== owner.day) {
owner._onPropertyChangedFromNative(common.DatePicker.dayProperty, comps.day);
}
}

View File

@@ -235,32 +235,42 @@ export class Frame extends frameCommon.Frame {
class UINavigationControllerImpl extends UINavigationController implements UINavigationControllerDelegate {
public static ObjCProtocols = [UINavigationControllerDelegate];
private _owner: Frame;
private _owner: WeakRef<Frame>;
public static initWithOwner(owner: Frame): UINavigationControllerImpl {
public static initWithOwner(owner: WeakRef<Frame>): UINavigationControllerImpl {
var controller = <UINavigationControllerImpl>UINavigationControllerImpl.new();
controller._owner = owner;
return controller;
}
get owner(): Frame {
return this._owner;
return this._owner.get();
}
public viewDidLoad(): void {
this._owner.onLoaded();
let owner = this._owner.get();
if (owner) {
owner.onLoaded();
}
}
public viewDidLayoutSubviews(): void {
trace.write(this._owner + " viewDidLayoutSubviews, isLoaded = " + this._owner.isLoaded, trace.categories.ViewHierarchy);
this._owner._updateLayout();
let owner = this._owner.get();
if (owner) {
trace.write(this._owner + " viewDidLayoutSubviews, isLoaded = " + owner.isLoaded, trace.categories.ViewHierarchy);
owner._updateLayout();
}
}
public navigationControllerWillShowViewControllerAnimated(navigationController: UINavigationController, viewController: UIViewController, animated: boolean): void {
// In this method we need to layout the new page otherwise page will be shown empty and update after that which is bad UX.
var frame = this._owner;
var newEntry: definition.BackstackEntry = viewController[ENTRY];
var newPage = newEntry.resolvedPage;
let frame = this._owner.get();
if (!frame) {
return;
}
let newEntry: definition.BackstackEntry = viewController[ENTRY];
let newPage = newEntry.resolvedPage;
if (!newPage.parent) {
if (!frame._currentEntry) {
// First navigation
@@ -282,14 +292,18 @@ class UINavigationControllerImpl extends UINavigationController implements UINav
}
public navigationControllerDidShowViewControllerAnimated(navigationController: UINavigationController, viewController: UIViewController, animated: boolean): void {
var frame: Frame = this._owner;
var backStack = frame.backStack;
var currentEntry = backStack.length > 0 ? backStack[backStack.length - 1] : null;
var newEntry: definition.BackstackEntry = viewController[ENTRY];
let frame = this._owner.get();
if (!frame) {
return;
}
let backStack = frame.backStack;
let currentEntry = backStack.length > 0 ? backStack[backStack.length - 1] : null;
let newEntry: definition.BackstackEntry = viewController[ENTRY];
// This code check if navigation happened through UI (e.g. back button or swipe gesture).
// When calling goBack on frame isBack will be false.
var isBack: boolean = currentEntry && newEntry === currentEntry;
let isBack: boolean = currentEntry && newEntry === currentEntry;
if (isBack) {
try {
frame._shouldSkipNativePop = true;
@@ -300,7 +314,7 @@ class UINavigationControllerImpl extends UINavigationController implements UINav
}
}
var page = frame.currentPage;
let page = frame.currentPage;
if (page && !navigationController.viewControllers.containsObject(page.ios)) {
frame._removeView(page);
}
@@ -308,7 +322,7 @@ class UINavigationControllerImpl extends UINavigationController implements UINav
frame._navigateToEntry = null;
frame._currentEntry = newEntry;
var newPage = newEntry.resolvedPage;
let newPage = newEntry.resolvedPage;
// In iOS we intentionally delay the raising of the 'loaded' event so both platforms behave identically.
// The loaded event must be raised AFTER the page is part of the windows hierarchy and
@@ -337,7 +351,7 @@ class iOSFrame implements definition.iOSFrame {
private _navBarVisibility: string;
constructor(owner: Frame) {
this._controller = UINavigationControllerImpl.initWithOwner(owner);
this._controller = UINavigationControllerImpl.initWithOwner(new WeakRef(owner));
this._controller.delegate = this._controller;
this._controller.automaticallyAdjustsScrollViewInsets = false;
//this.showNavigationBar = false;
@@ -356,8 +370,9 @@ class iOSFrame implements definition.iOSFrame {
this._showNavigationBar = value;
this._controller.navigationBarHidden = !value;
if (change) {
this._controller.owner.requestLayout();
let owner = this._controller.owner;
if (owner && change) {
owner.requestLayout();
}
}

View File

@@ -7,28 +7,26 @@ import trace = require("trace");
global.moduleMerge(common, exports);
class UIGestureRecognizerImpl extends NSObject {
static new(): UIGestureRecognizerImpl {
return <UIGestureRecognizerImpl>super.new();
}
private _owner: GesturesObserver;
private _owner: WeakRef<GesturesObserver>;
private _type: any;
private _callback: Function;
private _context: any;
public initWithOwnerTypeCallback(owner: GesturesObserver, type: any, callback?: Function, thisArg?: any): UIGestureRecognizerImpl {
this._owner = owner;
this._type = type;
public static initWithOwnerTypeCallback(owner: WeakRef<GesturesObserver>, type: any, callback?: Function, thisArg?: any): UIGestureRecognizerImpl {
let handler = <UIGestureRecognizerImpl>UIGestureRecognizerImpl.new();
handler._owner = owner;
handler._type = type;
if (callback) {
this._callback = callback;
handler._callback = callback;
}
if (thisArg) {
this._context = thisArg;
handler._context = thisArg;
}
return this;
return handler;
}
public static ObjCExposedMethods = {
@@ -36,17 +34,18 @@ class UIGestureRecognizerImpl extends NSObject {
};
public recognize(recognizer: UIGestureRecognizer): void {
var callback = this._callback ? this._callback : this._owner.callback;
var type = this._type;
var target = this._owner.target;
let owner = this._owner.get();
let callback = this._callback ? this._callback : (owner ? owner.callback : null);
let typeParam = this._type;
let target = owner ? owner.target : undefined;
var args = {
type: type,
type: typeParam,
view: target,
ios: recognizer,
android: undefined,
object: target,
eventName: definition.toString(type),
eventName: definition.toString(typeParam),
};
if (callback) {
@@ -209,7 +208,7 @@ export class GesturesObserver extends common.GesturesObserver {
}
function _createUIGestureRecognizerTarget(owner: GesturesObserver, type: definition.GestureTypes, callback?: (args: definition.GestureEventData) => void, thisArg?: any): any {
return UIGestureRecognizerImpl.new().initWithOwnerTypeCallback(owner, type, callback, thisArg);
return UIGestureRecognizerImpl.initWithOwnerTypeCallback(new WeakRef(owner), type, callback, thisArg);
}
interface RecognizerCache {

View File

@@ -24,35 +24,44 @@ function onTextWrapPropertyChanged(data: dependencyObservable.PropertyChangeData
global.moduleMerge(common, exports);
class UILabelImpl extends UILabel {
static new(): UILabelImpl {
return <UILabelImpl>super.new();
}
private _owner: Label;
private _owner: WeakRef<Label>;
public initWithOwner(owner: Label): UILabelImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<Label>): UILabelImpl {
let labelImpl = <UILabelImpl>UILabelImpl.new();
labelImpl._owner = owner;
return labelImpl;
}
public textRectForBoundsLimitedToNumberOfLines(bounds: CGRect, numberOfLines: number): CGRect {
var rect = super.textRectForBoundsLimitedToNumberOfLines(bounds, numberOfLines);
var textRect = CGRectMake(
- (this._owner.borderWidth + this._owner.style.paddingLeft),
- (this._owner.borderWidth + this._owner.style.paddingTop),
rect.size.width + (this._owner.borderWidth + this._owner.style.paddingLeft + this._owner.style.paddingRight + this._owner.borderWidth),
rect.size.height + (this._owner.borderWidth + this._owner.style.paddingTop + this._owner.style.paddingBottom + this._owner.borderWidth)
let rect = super.textRectForBoundsLimitedToNumberOfLines(bounds, numberOfLines);
let owner = this._owner.get();
if (owner) {
let size = rect.size;
rect = CGRectMake(
- (owner.borderWidth + owner.style.paddingLeft),
- (owner.borderWidth + owner.style.paddingTop),
size.width + (owner.borderWidth + owner.style.paddingLeft + owner.style.paddingRight + owner.borderWidth),
size.height + (owner.borderWidth + owner.style.paddingTop + owner.style.paddingBottom + owner.borderWidth)
);
return textRect;
}
return rect;
}
public drawTextInRect(rect: CGRect): void {
var textRect = CGRectMake(
(this._owner.borderWidth + this._owner.style.paddingLeft),
(this._owner.borderWidth + this._owner.style.paddingTop),
rect.size.width - (this._owner.borderWidth + this._owner.style.paddingLeft + this._owner.style.paddingRight + this._owner.borderWidth),
rect.size.height - (this._owner.borderWidth + this._owner.style.paddingTop + this._owner.style.paddingBottom + this._owner.borderWidth)
);
let owner = this._owner.get();
let textRect: CGRect;
let size = rect.size;
if (owner) {
textRect = CGRectMake((owner.borderWidth + owner.style.paddingLeft), (owner.borderWidth + owner.style.paddingTop),
size.width - (owner.borderWidth + owner.style.paddingLeft + owner.style.paddingRight + owner.borderWidth),
size.height - (owner.borderWidth + owner.style.paddingTop + owner.style.paddingBottom + owner.borderWidth));
}
else {
textRect = CGRectMake(0, 0, size.width, size.height);
}
super.drawTextInRect(textRect);
}
}
@@ -63,8 +72,7 @@ export class Label extends common.Label {
constructor(options?: definition.Options) {
super(options);
//this._ios = new UILabel();
this._ios = UILabelImpl.new().initWithOwner(this);
this._ios = UILabelImpl.initWithOwner(new WeakRef(this));
this._ios.userInteractionEnabled = true;
}

View File

@@ -13,13 +13,8 @@ export class ListPicker extends common.ListPicker {
super();
this._ios = new UIPickerView();
var dataSource = ListPickerDataSource.new().initWithOwner(this);
this._dataSource = dataSource;
this._ios.dataSource = this._dataSource;
this._delegate = ListPickerDelegateImpl.new().initWithOwner(this);
this._ios.dataSource = this._dataSource = ListPickerDataSource.initWithOwner(new WeakRef(this));
this._delegate = ListPickerDelegateImpl.initWithOwner(new WeakRef(this));
}
public onLoaded() {
@@ -55,16 +50,13 @@ export class ListPicker extends common.ListPicker {
class ListPickerDataSource extends NSObject implements UIPickerViewDataSource {
public static ObjCProtocols = [UIPickerViewDataSource];
private _owner: WeakRef<ListPicker>;
static new(): ListPickerDataSource {
return <ListPickerDataSource>super.new();
}
private _owner: ListPicker;
public initWithOwner(owner: ListPicker): ListPickerDataSource {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<ListPicker>): ListPickerDataSource {
let dataSource = <ListPickerDataSource>ListPickerDataSource.new();
dataSource._owner = owner;
return dataSource;
}
public numberOfComponentsInPickerView(pickerView: UIPickerView) {
@@ -72,35 +64,35 @@ class ListPickerDataSource extends NSObject implements UIPickerViewDataSource {
}
public pickerViewNumberOfRowsInComponent(pickerView: UIPickerView, component: number) {
return this._owner.items ? this._owner.items.length : 0;
let owner = this._owner.get();
return (owner && owner.items) ? owner.items.length : 0;
}
}
class ListPickerDelegateImpl extends NSObject implements UIPickerViewDelegate {
public static ObjCProtocols = [UIPickerViewDelegate];
static new(): ListPickerDelegateImpl {
return <ListPickerDelegateImpl>super.new();
}
private _owner: WeakRef<ListPicker>;
private _owner: ListPicker;
public initWithOwner(owner: ListPicker): ListPickerDelegateImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<ListPicker>): ListPickerDelegateImpl {
let delegate = <ListPickerDelegateImpl>ListPickerDelegateImpl.new();
delegate._owner = owner;
return delegate;
}
public pickerViewTitleForRowForComponent(pickerView: UIPickerView, row: number, component: number): string {
if (this._owner) {
return this._owner._getItemAsString(row);
let owner = this._owner.get();
if (owner) {
return owner._getItemAsString(row);
}
return row.toString();
}
public pickerViewDidSelectRowInComponent(pickerView: UIPickerView, row: number, component: number): void {
if (this._owner) {
this._owner._onPropertyChangedFromNative(common.ListPicker.selectedIndexProperty, row);
let owner = this._owner.get();
if (owner) {
owner._onPropertyChangedFromNative(common.ListPicker.selectedIndexProperty, row);
}
}
}

View File

@@ -18,13 +18,25 @@ global.moduleMerge(common, exports);
var infinity = utils.layout.makeMeasureSpec(0, utils.layout.UNSPECIFIED);
class ListViewCell extends UITableViewCell {
static new(): ListViewCell {
return <ListViewCell>super.new();
public willMoveToSuperview(newSuperview: UIView): void {
let parent: ListView = <ListView>(this.view ? this.view.parent : null);
// When inside ListView and there is no newSuperview this cell is
// removed from native visual tree so we remove it from our tree too.
if (parent && !newSuperview) {
parent._removeContainer(this);
}
}
public get view(): view.View {
return this.owner ? this.owner.get() : null
}
public owner: WeakRef<view.View>;
}
function notifyForItemAtIndex(listView: definition.ListView, cell: any, eventName: string, indexPath: NSIndexPath) {
var args = <definition.ItemEventData>{ eventName: eventName, object: listView, index: indexPath.row, view: cell.view, ios: cell, android: undefined };
function notifyForItemAtIndex(listView: definition.ListView, cell: any, view: view.View, eventName: string, indexPath: NSIndexPath) {
let args = <definition.ItemEventData>{ eventName: eventName, object: listView, index: indexPath.row, view: view, ios: cell, android: undefined };
listView.notify(args);
return args;
}
@@ -32,35 +44,35 @@ function notifyForItemAtIndex(listView: definition.ListView, cell: any, eventNam
class DataSource extends NSObject implements UITableViewDataSource {
public static ObjCProtocols = [UITableViewDataSource];
static new(): DataSource {
return <DataSource>super.new();
}
private _owner: WeakRef<ListView>;
private _owner: ListView;
public initWithOwner(owner: ListView): DataSource {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<ListView>): DataSource {
let dataSource = <DataSource>DataSource.new();
dataSource._owner = owner;
return dataSource;
}
public tableViewNumberOfRowsInSection(tableView: UITableView, section: number) {
return this._owner.items ? this._owner.items.length : 0;
let owner = this._owner.get();
return (owner && owner.items) ? owner.items.length : 0;
}
public tableViewCellForRowAtIndexPath(tableView: UITableView, indexPath: NSIndexPath): UITableViewCell {
// We call this method because ...ForIndexPath calls tableViewHeightForRowAtIndexPath immediately (before we can prepare and measure it).
var cell = tableView.dequeueReusableCellWithIdentifier(CELLIDENTIFIER) || ListViewCell.new();
this._owner._prepareCell(cell, indexPath);
let cell = <ListViewCell>(tableView.dequeueReusableCellWithIdentifier(CELLIDENTIFIER) || ListViewCell.new());
let owner = this._owner.get();
if (owner) {
owner._prepareCell(cell, indexPath);
var cellView: view.View = cell.view;
if (cellView) {
// Arrange cell views. We do it here instead of _layoutCell because _layoutCell is called
// from 'tableViewHeightForRowAtIndexPath' method too (in iOS 7.1) and we don't want to arrange the fake cell.
var width = utils.layout.getMeasureSpecSize(this._owner.widthMeasureSpec);
var cellHeight = this._owner.getHeight(indexPath.row);
view.View.layoutChild(this._owner, cellView, 0, 0, width, cellHeight);
let cellView: view.View = cell.view;
if (cellView) {
// Arrange cell views. We do it here instead of _layoutCell because _layoutCell is called
// from 'tableViewHeightForRowAtIndexPath' method too (in iOS 7.1) and we don't want to arrange the fake cell.
let width = utils.layout.getMeasureSpecSize(owner.widthMeasureSpec);
let cellHeight = owner.getHeight(indexPath.row);
view.View.layoutChild(owner, cellView, 0, 0, width, cellHeight);
}
}
return cell;
}
}
@@ -68,45 +80,52 @@ class DataSource extends NSObject implements UITableViewDataSource {
class UITableViewDelegateImpl extends NSObject implements UITableViewDelegate {
public static ObjCProtocols = [UITableViewDelegate];
static new(): UITableViewDelegateImpl {
return <UITableViewDelegateImpl>super.new();
}
private _owner: WeakRef<ListView>;
private _measureCell: ListViewCell;
private _owner: ListView;
private _measureCell: UITableViewCell;
public initWithOwner(owner: ListView): UITableViewDelegateImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<ListView>): UITableViewDelegateImpl {
let delegate = <UITableViewDelegateImpl>UITableViewDelegateImpl.new();
delegate._owner = owner;
return delegate;
}
public tableViewWillDisplayCellForRowAtIndexPath(tableView: UITableView, cell: UITableViewCell, indexPath: NSIndexPath) {
if (indexPath.row === this._owner.items.length - 1) {
this._owner.notify(<observable.EventData>{ eventName: LOADMOREITEMS, object: this._owner });
let owner = this._owner.get();
if (owner && (indexPath.row === owner.items.length - 1)) {
owner.notify(<observable.EventData>{ eventName: LOADMOREITEMS, object: owner });
}
}
public tableViewWillSelectRowAtIndexPath(tableView: UITableView, indexPath: NSIndexPath): NSIndexPath {
var cell = tableView.cellForRowAtIndexPath(indexPath);
notifyForItemAtIndex(this._owner, cell, ITEMTAP, indexPath);
let cell = <ListViewCell>tableView.cellForRowAtIndexPath(indexPath);
let owner = this._owner.get();
if (owner) {
notifyForItemAtIndex(owner, cell, cell.view, ITEMTAP, indexPath);
}
cell.highlighted = false;
return indexPath;
}
public tableViewHeightForRowAtIndexPath(tableView: UITableView, indexPath: NSIndexPath): number {
var height = undefined;
if (utils.ios.MajorVersion >= 8) {
height = this._owner.getHeight(indexPath.row);
let owner = this._owner.get();
if (!owner) {
return 44;
}
let height = undefined;
if (utils.ios.MajorVersion >= 8) {
height = owner.getHeight(indexPath.row);
}
if (utils.ios.MajorVersion < 8 || height === undefined) {
// in iOS 7.1 (or iOS8+ after call to scrollToRowAtIndexPath:atScrollPosition:animated:) this method is called before tableViewCellForRowAtIndexPath so we need fake cell to measure its content.
var cell = this._measureCell;
let cell = this._measureCell;
if (!cell) {
this._measureCell = tableView.dequeueReusableCellWithIdentifier(CELLIDENTIFIER) || ListViewCell.new();
cell = this._measureCell;
}
height = this._owner._prepareCell(cell, indexPath);
height = owner._prepareCell(cell, indexPath);
}
return height;
@@ -134,7 +153,7 @@ export class ListView extends common.ListView {
private _heights: Array<number>;
private _preparingCell: boolean = false;
private _isDataDirty: boolean = false;
private _map: Map<ListViewCell, view.View>;
widthMeasureSpec: number = 0;
constructor() {
@@ -145,14 +164,10 @@ export class ListView extends common.ListView {
this._ios.autoresizingMask = UIViewAutoresizing.UIViewAutoresizingNone;
this._ios.estimatedRowHeight = DEFAULT_HEIGHT;
var dataSource = DataSource.new().initWithOwner(this);
this._dataSource = dataSource;
this._ios.dataSource = this._dataSource;
this._delegate = UITableViewDelegateImpl.new().initWithOwner(this);
this._ios.dataSource = this._dataSource = DataSource.initWithOwner(new WeakRef(this));
this._delegate = UITableViewDelegateImpl.initWithOwner(new WeakRef(this));
this._heights = new Array<number>();
this._map = new Map<ListViewCell, view.View>();
}
public onLoaded() {
@@ -225,22 +240,34 @@ export class ListView extends common.ListView {
return 0;
}
public _prepareCell(tableCell: UITableViewCell, indexPath: NSIndexPath): number {
var cell: any = tableCell;
var cellHeight: number;
public _prepareCell(cell: ListViewCell, indexPath: NSIndexPath): number {
let cellHeight: number;
try {
this._preparingCell = true;
if (!cell.view) {
cell.view = this._getItemTemplateContent(indexPath.row);
let view = cell.view;
if (!view) {
view = this._getItemTemplateContent(indexPath.row);
}
var args = notifyForItemAtIndex(this, cell, ITEMLOADING, indexPath);
var view = cell.view = args.view || this._getDefaultItemContent(indexPath.row);
let args = notifyForItemAtIndex(this, cell, view, ITEMLOADING, indexPath);
view = args.view || this._getDefaultItemContent(indexPath.row);
// If cell is reused be have old content - remove it first.
if (!cell.view) {
cell.owner = new WeakRef(view);
}
else if (cell.view !== view) {
this._removeContainer(cell);
(<UIView>cell.view._nativeView).removeFromSuperview();
cell.owner = new WeakRef(view);
}
this._prepareItem(view, indexPath.row);
if (view && !view.parent && view.ios) {
cell.contentView.addSubview(view.ios);
this._map.set(cell, view);
// We expect that views returned from itemLoading are new (e.g. not reused).
if (view && !view.parent && view._nativeView) {
cell.contentView.addSubview(view._nativeView);
this._addView(view);
}
@@ -251,4 +278,9 @@ export class ListView extends common.ListView {
}
return cellHeight;
}
public _removeContainer(cell: ListViewCell): void {
this._removeView(cell.view)
this._map.delete(cell);
}
}

View File

@@ -11,35 +11,30 @@ import observable = require("data/observable");
global.moduleMerge(pageCommon, exports);
class UIViewControllerImpl extends UIViewController {
static new(): UIViewControllerImpl {
return <UIViewControllerImpl>super.new();
}
private _owner: Page;
private _owner: WeakRef<Page>;
public initWithOwner(owner: Page): UIViewControllerImpl {
this._owner = owner;
this.automaticallyAdjustsScrollViewInsets = false;
return this;
}
public didRotateFromInterfaceOrientation(fromInterfaceOrientation: number) {
trace.write(this._owner + " didRotateFromInterfaceOrientation(" + fromInterfaceOrientation + ")", trace.categories.ViewHierarchy);
}
public viewDidLoad() {
trace.write(this._owner + " viewDidLoad", trace.categories.ViewHierarchy);
public static initWithOwner(owner: WeakRef<Page>): UIViewControllerImpl {
let controller = <UIViewControllerImpl>UIViewControllerImpl.new();
controller._owner = owner;
controller.automaticallyAdjustsScrollViewInsets = false;
return controller;
}
public viewDidLayoutSubviews() {
trace.write(this._owner + " viewDidLayoutSubviews, isLoaded = " + this._owner.isLoaded, trace.categories.ViewHierarchy);
if (!this._owner.isLoaded) {
let owner = this._owner.get();
if (!owner) {
return;
}
trace.write(owner + " viewDidLayoutSubviews, isLoaded = " + owner.isLoaded, trace.categories.ViewHierarchy);
if (!owner.isLoaded) {
return;
}
if (this._owner._isModal) {
if (owner._isModal) {
let isTablet = device.deviceType === DeviceType.Tablet;
let isFullScreen = !this._owner._UIModalPresentationFormSheet || !isTablet;
let isFullScreen = !owner._UIModalPresentationFormSheet || !isTablet;
let frame = isFullScreen ? UIScreen.mainScreen().bounds : this.view.frame;
let origin = frame.origin;
let size = frame.size;
@@ -62,7 +57,7 @@ class UIViewControllerImpl extends UIViewController {
let bottom = height;
let statusBarHeight = uiUtils.ios.getStatusBarHeight();
let statusBarVisible = !UIApplication.sharedApplication().statusBarHidden;
let backgroundSpanUnderStatusBar = this._owner.backgroundSpanUnderStatusBar;
let backgroundSpanUnderStatusBar = owner.backgroundSpanUnderStatusBar;
if (statusBarVisible && !backgroundSpanUnderStatusBar) {
height -= statusBarHeight;
}
@@ -70,9 +65,9 @@ class UIViewControllerImpl extends UIViewController {
let widthSpec = utils.layout.makeMeasureSpec(width, mode);
let heightSpec = utils.layout.makeMeasureSpec(height, mode);
View.measureChild(null, this._owner, widthSpec, heightSpec);
View.measureChild(null, owner, widthSpec, heightSpec);
let top = ((backgroundSpanUnderStatusBar && isFullScreen) || utils.ios.MajorVersion < 8 || !isFullScreen) ? 0 : statusBarHeight;
View.layoutChild(null, this._owner, 0, top, width, bottom);
View.layoutChild(null, owner, 0, top, width, bottom);
if (utils.ios.MajorVersion < 8) {
if (!backgroundSpanUnderStatusBar && (!isTablet || isFullScreen)) {
@@ -88,31 +83,41 @@ class UIViewControllerImpl extends UIViewController {
trace.write(this._owner + ", native frame = " + NSStringFromCGRect(this.view.frame), trace.categories.Layout);
}
else {
this._owner._updateLayout();
owner._updateLayout();
}
}
public viewWillAppear() {
trace.write(this._owner + " viewWillAppear", trace.categories.Navigation);
this._owner._enableLoadedEvents = true;
let owner = this._owner.get();
if (!owner) {
return;
}
trace.write(owner + " viewWillAppear", trace.categories.Navigation);
owner._enableLoadedEvents = true;
// In iOS we intentionally delay the raising of the 'loaded' event so both platforms behave identically.
// The loaded event must be raised AFTER the page is part of the windows hierarchy and
// frame.topmost().currentPage is set to the page instance.
// https://github.com/NativeScript/NativeScript/issues/779
if (!this._owner._isModal) {
this._owner._delayLoadedEvent = true;
if (!owner._isModal) {
owner._delayLoadedEvent = true;
}
this._owner.onLoaded();
this._owner._enableLoadedEvents = false;
owner.onLoaded();
owner._enableLoadedEvents = false;
}
public viewDidDisappear() {
trace.write(this._owner + " viewDidDisappear", trace.categories.Navigation);
this._owner._enableLoadedEvents = true;
this._owner.onUnloaded();
this._owner._enableLoadedEvents = false;
let owner = this._owner.get();
if (!owner) {
return;
}
trace.write(owner + " viewDidDisappear", trace.categories.Navigation);
owner._enableLoadedEvents = true;
owner.onUnloaded();
owner._enableLoadedEvents = false;
}
}
@@ -125,7 +130,7 @@ export class Page extends pageCommon.Page {
constructor(options?: definition.Options) {
super(options);
this._ios = UIViewControllerImpl.new().initWithOwner(this);
this._ios = UIViewControllerImpl.initWithOwner(new WeakRef(this));
}
public requestLayout(): void {

View File

@@ -57,24 +57,26 @@ global.moduleMerge(common, exports);
class UISearchBarDelegateImpl extends NSObject implements UISearchBarDelegate {
public static ObjCProtocols = [UISearchBarDelegate];
static new(): UISearchBarDelegateImpl {
return <UISearchBarDelegateImpl>super.new();
}
private _owner: SearchBar;
private _owner: WeakRef<SearchBar>;
private _searchText: string;
public initWithOwner(owner: SearchBar): UISearchBarDelegateImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<SearchBar>): UISearchBarDelegateImpl {
let delegate = <UISearchBarDelegateImpl>UISearchBarDelegateImpl.new();
delegate._owner = owner;
return delegate;
}
public searchBarTextDidChange(searchBar: UISearchBar, searchText: string) {
this._owner._onPropertyChangedFromNative(common.SearchBar.textProperty, searchText);
let owner = this._owner.get();
if (!owner) {
return;
}
owner._onPropertyChangedFromNative(common.SearchBar.textProperty, searchText);
// This code is needed since sometimes searchBarCancelButtonClicked is not called!
if (searchText === "" && this._searchText !== searchText) {
this._owner._emit(common.SearchBar.clearEvent);
owner._emit(common.SearchBar.clearEvent);
}
this._searchText = searchText;
@@ -82,12 +84,22 @@ class UISearchBarDelegateImpl extends NSObject implements UISearchBarDelegate {
public searchBarCancelButtonClicked(searchBar: UISearchBar) {
searchBar.resignFirstResponder();
this._owner._emit(common.SearchBar.clearEvent);
let owner = this._owner.get();
if (!owner) {
return;
}
owner._emit(common.SearchBar.clearEvent);
}
public searchBarSearchButtonClicked(searchBar: UISearchBar) {
searchBar.resignFirstResponder();
this._owner._emit(common.SearchBar.submitEvent);
let owner = this._owner.get();
if (!owner) {
return;
}
owner._emit(common.SearchBar.submitEvent);
}
}
@@ -101,7 +113,7 @@ export class SearchBar extends common.SearchBar {
this._ios = new UISearchBar();
this._delegate = UISearchBarDelegateImpl.new().initWithOwner(this);
this._delegate = UISearchBarDelegateImpl.initWithOwner(new WeakRef(this));
}
public onLoaded() {
@@ -121,7 +133,7 @@ export class SearchBar extends common.SearchBar {
get ios(): UISearchBar {
return this._ios;
}
}
private static findTextField(view: UIView) {
for (let i = 0, l = view.subviews.count; i < l; i++) {

View File

@@ -86,7 +86,7 @@ export class SegmentedBar extends common.SegmentedBar {
super();
this._ios = UISegmentedControl.new();
this._selectionHandler = SelectionHandlerImpl.new().initWithOwner(this);
this._selectionHandler = SelectionHandlerImpl.initWithOwner(new WeakRef(this));
this._ios.addTargetActionForControlEvents(this._selectionHandler, "selected", UIControlEvents.UIControlEventValueChanged);
}
@@ -96,22 +96,23 @@ export class SegmentedBar extends common.SegmentedBar {
}
class SelectionHandlerImpl extends NSObject {
static new(): SelectionHandlerImpl {
return <SelectionHandlerImpl>super.new();
}
private _owner: SegmentedBar;
private _owner: WeakRef<SegmentedBar>;
public initWithOwner(owner: SegmentedBar): SelectionHandlerImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<SegmentedBar>): SelectionHandlerImpl {
let handler = <SelectionHandlerImpl>SelectionHandlerImpl.new();
handler._owner = owner;
return handler;
}
public selected(sender: UISegmentedControl) {
this._owner.selectedIndex = sender.selectedSegmentIndex;
let owner = this._owner.get();
if (owner) {
owner.selectedIndex = sender.selectedSegmentIndex;
}
}
public static ObjCExposedMethods = {
"selected": { returns: interop.types.void, params: [UISegmentedControl] }
};
}
}

View File

@@ -25,19 +25,20 @@ function onMaxValuePropertyChanged(data: dependencyObservable.PropertyChangeData
global.moduleMerge(common, exports);
class SliderChangeHandlerImpl extends NSObject {
static new(): SliderChangeHandlerImpl {
return <SliderChangeHandlerImpl>super.new();
private _owner: WeakRef<Slider>;
public static initWithOwner(owner: WeakRef<Slider>): SliderChangeHandlerImpl {
let handler = <SliderChangeHandlerImpl>SliderChangeHandlerImpl.new();
handler._owner = owner;
return handler;
}
private _owner: Slider;
public initWithOwner(owner: Slider): SliderChangeHandlerImpl {
this._owner = owner;
return this;
}
public sliderValueChanged(sender: UISlider) {
this._owner._onPropertyChangedFromNative(common.Slider.valueProperty, sender.value);
let owner = this._owner.get();
if (owner) {
owner._onPropertyChangedFromNative(common.Slider.valueProperty, sender.value);
}
}
public static ObjCExposedMethods = {
@@ -57,7 +58,7 @@ export class Slider extends common.Slider {
this._ios.minimumValue = 0;
this._ios.maximumValue = this.maxValue;
this._changeHandler = SliderChangeHandlerImpl.new().initWithOwner(this);
this._changeHandler = SliderChangeHandlerImpl.initWithOwner(new WeakRef(this));
this._ios.addTargetActionForControlEvents(this._changeHandler, "sliderValueChanged", UIControlEvents.UIControlEventValueChanged);
}

View File

@@ -13,19 +13,20 @@ function onCheckedPropertyChanged(data: dependencyObservable.PropertyChangeData)
global.moduleMerge(common, exports);
class SwitchChangeHandlerImpl extends NSObject {
static new(): SwitchChangeHandlerImpl {
return <SwitchChangeHandlerImpl>super.new();
}
private _owner: Switch;
private _owner: WeakRef<Switch>;
public initWithOwner(owner: Switch): SwitchChangeHandlerImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<Switch>): SwitchChangeHandlerImpl {
let handler = <SwitchChangeHandlerImpl>SwitchChangeHandlerImpl.new();
handler._owner = owner;
return handler;
}
public valueChanged(sender: UISwitch) {
this._owner._onPropertyChangedFromNative(common.Switch.checkedProperty, sender.on);
let owner = this._owner.get();
if (owner) {
owner._onPropertyChangedFromNative(common.Switch.checkedProperty, sender.on);
}
}
public static ObjCExposedMethods = {
@@ -41,7 +42,7 @@ export class Switch extends common.Switch {
super();
this._ios = new UISwitch();
this._handler = SwitchChangeHandlerImpl.new().initWithOwner(this);
this._handler = SwitchChangeHandlerImpl.initWithOwner(new WeakRef(this));
this._ios.addTargetActionForControlEvents(this._handler, "valueChanged", UIControlEvents.UIControlEventValueChanged);
}

View File

@@ -13,22 +13,21 @@ import color = require("color");
global.moduleMerge(common, exports);
class UITabBarControllerImpl extends UITabBarController {
static new(): UITabBarControllerImpl {
return <UITabBarControllerImpl>super.new();
}
private _owner: TabView;
private _owner: WeakRef<TabView>;
public initWithOwner(owner: TabView): UITabBarControllerImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<TabView>): UITabBarControllerImpl {
let handler = <UITabBarControllerImpl>UITabBarControllerImpl.new();
handler._owner = owner;
return handler;
}
public viewDidLayoutSubviews(): void {
trace.write("TabView.UITabBarControllerClass.viewDidLayoutSubviews();", trace.categories.Debug);
super.viewDidLayoutSubviews();
if (this._owner.isLoaded) {
this._owner._updateLayout();
let owner = this._owner.get();
if (owner && owner.isLoaded) {
owner._updateLayout();
}
}
}
@@ -36,42 +35,42 @@ class UITabBarControllerImpl extends UITabBarController {
class UITabBarControllerDelegateImpl extends NSObject implements UITabBarControllerDelegate {
public static ObjCProtocols = [UITabBarControllerDelegate];
static new(): UITabBarControllerDelegateImpl {
return <UITabBarControllerDelegateImpl>super.new();
}
private _owner: WeakRef<TabView>;
private _owner: TabView;
public initWithOwner(owner: TabView): UITabBarControllerDelegateImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<TabView>): UITabBarControllerDelegateImpl {
let delegate = <UITabBarControllerDelegateImpl>UITabBarControllerDelegateImpl.new();
delegate._owner = owner;
return delegate;
}
public tabBarControllerDidSelectViewController(tabBarController: UITabBarController, viewController: UIViewController): void {
trace.write("TabView.UITabBarControllerDelegateClass.tabBarControllerDidSelectViewController(" + tabBarController + ", " + viewController + ");", trace.categories.Debug);
this._owner._onViewControllerShown(viewController);
let owner = this._owner.get();
if (owner) {
owner._onViewControllerShown(viewController);
}
}
}
class UINavigationControllerDelegateImpl extends NSObject implements UINavigationControllerDelegate {
public static ObjCProtocols = [UINavigationControllerDelegate];
static new(): UINavigationControllerDelegateImpl {
return <UINavigationControllerDelegateImpl>super.new();
}
private _owner: WeakRef<TabView>;
private _owner: TabView;
public initWithOwner(owner: TabView): UINavigationControllerDelegateImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<TabView>): UINavigationControllerDelegateImpl {
let delegate = <UINavigationControllerDelegateImpl>UINavigationControllerDelegateImpl.new();
delegate._owner = owner;
return delegate;
}
navigationControllerDidShowViewControllerAnimated(navigationController: UINavigationController, viewController: UIViewController, animated: boolean): void {
trace.write("TabView.UINavigationControllerDelegateClass.navigationControllerDidShowViewControllerAnimated(" + navigationController + ", " + viewController + ", " + animated + ");", trace.categories.Debug);
// We don't need Edit button in More screen.
navigationController.navigationBar.topItem.rightBarButtonItem = null;
this._owner._onViewControllerShown(viewController);
let owner = this._owner.get();
if (owner) {
owner._onViewControllerShown(viewController);
}
}
}
@@ -117,11 +116,9 @@ export class TabView extends common.TabView {
constructor() {
super();
this._ios = UITabBarControllerImpl.new().initWithOwner(this);
this._delegate = UITabBarControllerDelegateImpl.new().initWithOwner(this);
this._moreNavigationControllerDelegate = UINavigationControllerDelegateImpl.new().initWithOwner(this);
this._ios = UITabBarControllerImpl.initWithOwner(new WeakRef(this));
this._delegate = UITabBarControllerDelegateImpl.initWithOwner(new WeakRef(this));
this._moreNavigationControllerDelegate = UINavigationControllerDelegateImpl.initWithOwner(new WeakRef(this));
//This delegate is set on the last line of _addTabs method.
}

View File

@@ -16,85 +16,99 @@ global.moduleMerge(common, exports);
class UITextFieldDelegateImpl extends NSObject implements UITextFieldDelegate {
public static ObjCProtocols = [UITextFieldDelegate];
static new(): UITextFieldDelegateImpl {
return <UITextFieldDelegateImpl>super.new();
private _owner: WeakRef<TextField>;
private firstEdit: boolean;
public static initWithOwner(owner: WeakRef<TextField>): UITextFieldDelegateImpl {
let delegate = <UITextFieldDelegateImpl>UITextFieldDelegateImpl.new();
delegate._owner = owner;
return delegate;
}
private _owner: TextField;
private firstEdit: boolean;
public initWithOwner(owner: TextField): UITextFieldDelegateImpl {
this._owner = owner;
return this;
}
public textFieldShouldBeginEditing(textField: UITextField): boolean {
this.firstEdit = true;
return this._owner.editable;
let owner = this._owner.get();
if (owner) {
return owner.editable;
}
return true;
}
public textFieldDidEndEditing(textField: UITextField) {
if (this._owner.updateTextTrigger === enums.UpdateTextTrigger.focusLost) {
this._owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, textField.text);
}
let owner = this._owner.get();
if (owner) {
if (owner.updateTextTrigger === enums.UpdateTextTrigger.focusLost) {
owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, textField.text);
}
this._owner.dismissSoftInput();
owner.dismissSoftInput();
}
}
public textFieldShouldClear(textField: UITextField) {
this.firstEdit = false;
this._owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, "");
let owner = this._owner.get();
if (owner) {
owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, "");
}
return true;
}
public textFieldShouldReturn(textField: UITextField): boolean {
// Called when the user presses the return button.
this._owner.dismissSoftInput();
this._owner.notify({ eventName: TextField.returnPressEvent, object: this._owner });
let owner = this._owner.get();
if (owner) {
owner.dismissSoftInput();
owner.notify({ eventName: TextField.returnPressEvent, object: owner });
}
return true;
}
public textFieldShouldChangeCharactersInRangeReplacementString(textField: UITextField, range: NSRange, replacementString: string): boolean {
if (this._owner.updateTextTrigger === enums.UpdateTextTrigger.textChanged) {
if (textField.secureTextEntry && this.firstEdit) {
this._owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, replacementString);
}
else {
var newText = NSString.alloc().initWithString(textField.text).stringByReplacingCharactersInRangeWithString(range, replacementString);
this._owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, newText);
let owner = this._owner.get();
if (owner) {
if (owner.updateTextTrigger === enums.UpdateTextTrigger.textChanged) {
if (textField.secureTextEntry && this.firstEdit) {
owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, replacementString);
}
else {
let newText = NSString.alloc().initWithString(textField.text).stringByReplacingCharactersInRangeWithString(range, replacementString);
owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, newText);
}
}
}
this.firstEdit = false;
this.firstEdit = false;
return true;
}
}
class UITextFieldImpl extends UITextField {
static new(): UITextFieldImpl {
return <UITextFieldImpl>super.new();
}
private _owner: TextField;
private _owner: WeakRef<TextField>;
public initWithOwner(owner: TextField): UITextFieldImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<TextField>): UITextFieldImpl {
let handler = <UITextFieldImpl>UITextFieldImpl.new();
handler._owner = owner;
return handler;
}
private _getTextRectForBounds(bounds: CGRect): CGRect {
if (!this._owner) {
let owner = this._owner ? this._owner.get() : null;
if (!owner) {
return bounds;
}
return CGRectMake(
this._owner.borderWidth + this._owner.style.paddingLeft,
this._owner.borderWidth + this._owner.style.paddingTop,
bounds.size.width - (this._owner.borderWidth + this._owner.style.paddingLeft + this._owner.style.paddingRight + this._owner.borderWidth),
bounds.size.height - (this._owner.borderWidth + this._owner.style.paddingTop + this._owner.style.paddingBottom + this._owner.borderWidth)
);
let size = bounds.size;
return CGRectMake(owner.borderWidth + owner.style.paddingLeft, owner.borderWidth + owner.style.paddingTop,
size.width - (owner.borderWidth + owner.style.paddingLeft + owner.style.paddingRight + owner.borderWidth),
size.height - (owner.borderWidth + owner.style.paddingTop + owner.style.paddingBottom + owner.borderWidth)
);
}
public textRectForBounds(bounds: CGRect): CGRect {
return this._getTextRectForBounds(bounds);
}
@@ -111,8 +125,8 @@ export class TextField extends common.TextField {
constructor() {
super();
this._ios = UITextFieldImpl.new().initWithOwner(this);
this._delegate = UITextFieldDelegateImpl.new().initWithOwner(this);
this._ios = UITextFieldImpl.initWithOwner(new WeakRef(this));
this._delegate = UITextFieldDelegateImpl.initWithOwner(new WeakRef(this));
}
public onLoaded() {

View File

@@ -38,7 +38,7 @@ export class TimePicker extends common.TimePicker {
this._ios = new UIDatePicker();
this._ios.datePickerMode = UIDatePickerMode.UIDatePickerModeTime;
this._changeHandler = UITimePickerChangeHandlerImpl.new().initWithOwner(this);
this._changeHandler = UITimePickerChangeHandlerImpl.initWithOwner(new WeakRef(this));
this._ios.addTargetActionForControlEvents(this._changeHandler, "valueChanged", UIControlEvents.UIControlEventValueChanged);
}
@@ -48,30 +48,33 @@ export class TimePicker extends common.TimePicker {
}
class UITimePickerChangeHandlerImpl extends NSObject {
static new(): UITimePickerChangeHandlerImpl {
return <UITimePickerChangeHandlerImpl>super.new();
}
private _owner: TimePicker;
private _owner: WeakRef<TimePicker>;
public initWithOwner(owner: TimePicker): UITimePickerChangeHandlerImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<TimePicker>): UITimePickerChangeHandlerImpl {
let handler = <UITimePickerChangeHandlerImpl>UITimePickerChangeHandlerImpl.new();
handler._owner = owner;
return handler;
}
public valueChanged(sender: UIDatePicker) {
var comps = NSCalendar.currentCalendar().componentsFromDate(NSCalendarUnit.NSCalendarUnitHour | NSCalendarUnit.NSCalendarUnitMinute, sender.date);
if (comps.hour !== this._owner.hour) {
this._owner._onPropertyChangedFromNative(common.TimePicker.hourProperty, comps.hour);
let owner = this._owner.get();
if (!owner) {
return;
}
if (comps.minute !== this._owner.minute) {
this._owner._onPropertyChangedFromNative(common.TimePicker.minuteProperty, comps.minute);
var comps = NSCalendar.currentCalendar().componentsFromDate(NSCalendarUnit.NSCalendarUnitHour | NSCalendarUnit.NSCalendarUnitMinute, sender.date);
if (comps.hour !== owner.hour) {
owner._onPropertyChangedFromNative(common.TimePicker.hourProperty, comps.hour);
}
if (comps.minute !== owner.minute) {
owner._onPropertyChangedFromNative(common.TimePicker.minuteProperty, comps.minute);
}
}
public static ObjCExposedMethods = {
'valueChanged': { returns: interop.types.void, params: [UIDatePicker] }
};
}
}

View File

@@ -6,21 +6,19 @@ global.moduleMerge(common, exports);
class UIWebViewDelegateImpl extends NSObject implements UIWebViewDelegate {
public static ObjCProtocols = [UIWebViewDelegate];
static new(): UIWebViewDelegateImpl {
return <UIWebViewDelegateImpl>super.new();
}
private _owner: WeakRef<WebView>;
private _owner: WebView;
public initWithOwner(owner: WebView): UIWebViewDelegateImpl {
this._owner = owner;
return this;
public static initWithOwner(owner: WeakRef<WebView>): UIWebViewDelegateImpl {
let delegate = <UIWebViewDelegateImpl>UIWebViewDelegateImpl.new();
delegate._owner = owner;
return delegate;
}
public webViewShouldStartLoadWithRequestNavigationType(webView: UIWebView, request: NSURLRequest, navigationType: number) {
if (request.URL) {
let owner = this._owner.get();
if (owner && request.URL) {
trace.write("UIWebViewDelegateClass.webViewShouldStartLoadWithRequestNavigationType(" + request.URL.absoluteString + ", " + navigationType + ")", trace.categories.Debug);
this._owner._onLoadStarted(request.URL.absoluteString);
owner._onLoadStarted(request.URL.absoluteString);
}
return true;
@@ -32,17 +30,25 @@ class UIWebViewDelegateImpl extends NSObject implements UIWebViewDelegate {
public webViewDidFinishLoad(webView: UIWebView) {
trace.write("UIWebViewDelegateClass.webViewDidFinishLoad(" + webView.request.URL + ")", trace.categories.Debug);
this._owner._onLoadFinished(webView.request.URL.absoluteString);
let owner = this._owner.get();
if (owner) {
owner._onLoadFinished(webView.request.URL.absoluteString);
}
}
public webViewDidFailLoadWithError(webView: UIWebView, error: NSError) {
var url = this._owner.url;
if (webView.request && webView.request.URL) {
url = webView.request.URL.absoluteString;
}
let owner = this._owner.get();
if (owner) {
var url = owner.url;
if (webView.request && webView.request.URL) {
url = webView.request.URL.absoluteString;
}
trace.write("UIWebViewDelegateClass.webViewDidFailLoadWithError(" + error.localizedDescription + ")", trace.categories.Debug);
this._owner._onLoadFinished(url, error.localizedDescription);
trace.write("UIWebViewDelegateClass.webViewDidFailLoadWithError(" + error.localizedDescription + ")", trace.categories.Debug);
if (owner) {
owner._onLoadFinished(url, error.localizedDescription);
}
}
}
}
@@ -54,7 +60,7 @@ export class WebView extends common.WebView {
super();
this._ios = new UIWebView();
this._delegate = UIWebViewDelegateImpl.new().initWithOwner(this);
this._delegate = UIWebViewDelegateImpl.initWithOwner(new WeakRef(this));
}
public onLoaded() {