monotouch开发ios应用手记

First of all,thanks to all the guys works for Xamarin, and the guys contribute to the monotouch community in stackoverflow and github,without your contribution I can't  finish this .
开发目标:一个办公系统的ios客户端,主要已数据的展示为主,兼顾待办事宜,邮件等的处理
开发思路:nativeapp+webapp,主体及列表展示使用monotouch开发,业务数据的展示页面使用webview展示服务器端返回的html,html在以字符串方式保存在sqlite中.
开发环境:lion+monodevelop(3.0.2)+monotouch(5.2)+xcode(4.3)
开发类库:monotoch.dialog(用于配置界面和数据列表展示界面的展示),monotouch-sqlite(数据的CURD及查询功能),ServiceStack.Text(json数据的处理),HtmlAgilityPack(数据的解码及编码),testflight(从官方的github中获取monotouch-binding下的类库编译用于异常的获取跟踪等)
类封装及框架参考:主体参考TweetStation,封装了滑动翻页(PagedViewController),进度显示(MBProgressHUD),对话框,webview等,参考monotouch-sample下的bubblecell结合webview实现了数据的处理界面(输入文字提交意见回复等)
待处理问题:内存使用过大,monotoch.dialog在构建root生成dialogviewcontroller时占用的内存较大,使用webview展示界面时耗费内存也较大,导致内存低时出现闪退。当前尽量使用全局变量以及增加参数控制必要时刻才进行dialogviewcontroller的创建,下一步需要使用profiler工具分析内存的使用情况。
遇到的问题及解决方法
问题一:输入密码后点击其他区域隐藏键盘(后来发现一行搞定:oTapRecognizer.CancelsTouchesInView=false;)
//solve the keybord didn't hide problem 
    public class TapGestureRecognizerDelegate : UIGestureRecognizerDelegate
    {
        public UITouch ActiveTouch { get; set; }
 
        public override bool ShouldReceiveTouch (UIGestureRecognizer recognizer, UITouch touch)
        {
            if (touch.View is UIButton)
                return false;
 
            ActiveTouch = touch;
 
            return true;
        }
    }

UITapGestureRecognizer oTapRecognizer = new UITapGestureRecognizer ();
            //oTapRecognizer.Delegate = new TapGestureRecognizerDelegate ();
            oTapRecognizer.CancelsTouchesInView = false;

            oTapRecognizer.AddTarget (
                this,
                new MonoTouch.ObjCRuntime.Selector ("ViewTappedSelector:")
            );
            this.View.AddGestureRecognizer (oTapRecognizer);

 

[Export( "ViewTappedSelector:" )]
        public void ViewTapped (UIGestureRecognizer sender)
        {
            
            this.fieldpassword.ResignFirstResponder ();//cancel the state
            this.fielduser.ResignFirstResponder ();
        }
问题二:MBProgressHUD在进行网络请求时只在数据返回时显示,这个问题了nsloop的运行方式有关,如果都在一个线程上的话网络请求阻塞了hud的显示,所以要使用异步的数据获取方式

 

            var loginurl = AppDelegate.apspdata.LoginUrl (
                    this.fielduser.Text,
                    this.fieldpassword.Text
            );
            if (hud == null) {
                hud = new MBProgressHUD (this.View.Window);
                hud.Mode = MBProgressHUDMode.Indeterminate;
                hud.TitleText = "Loading";
                hud.DetailText = "数据加载中";
                this.View.Window.AddSubview (hud);
            }
            hud.Show (true);
            try {
                Console.WriteLine (loginurl);
                using (WebClient client = new WebClient ()) {
                    client.Encoding = System.Text.Encoding.UTF8;
                    client.DownloadStringCompleted += (clientsender, cliente) => 
                    { 
                        hud.Hide (true);
                        try {
                            APSP.Form.Mobile.MobileLogin root = ServiceStack.Text.JsonSerializer.DeserializeFromString<APSP.Form.Mobile.MobileLogin> (cliente.Result);
                            if (!string.IsNullOrEmpty (root.userName)) {
                                var uc = AppDelegate.apspdata.CurrentUser;
                                uc.CHName = root.userName.Replace ("\"", "");
                                uc.UserName = fielduser.Text;
                                Database.Main.Update (uc);
                                PetroleumOAViewController pv1 = new PetroleumOAViewController ();
                                this.NavigationController.PushViewController (pv1, true);
                                Console.WriteLine ("load pageviewer");
                            } else {
                                MessageBox.Show (root.result.message);
                                return;
                            }
                        } catch (Exception ee) {
                            MessageBox.Show (ee.Message);
                        }


                    };
                    client.DownloadStringAsync (new Uri (loginurl));
                }
            

            } catch (Exception ex) {
                hud.Hide (true);
                MessageBox.Show (ex.Message);
            }

问题三:uiwebview缩放,使用本地资源,链接使用safari打开问题

<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.5; user-scalable=1"/>
basedir=NSBundle.MainBundle.BundlePath;
webview.LoadHtmlString(html,new NSUrl(basedir,true))
webView.ShouldStartLoad = delegate (UIWebView webViewParam, NSUrlRequest request, UIWebViewNavigationType navigationType) {    // Catch the link click, and process the add/remove favorites

                if (navigationType == UIWebViewNavigationType.LinkClicked) {
                    //string path = request.Url.Path.Substring(1);
                    //this.NavigationController.PushViewController (new WebViewController (request), true);
                    string opurl = request.Url.ToString ().Replace (
                        "file://",
                        AppDelegate.apspdata.CurrentUser.ServerPath
                    );
                    Console.WriteLine (opurl);
                    UIApplication.SharedApplication.OpenUrl (NSUrl.FromString (opurl));
                    return false;
                    //return false;
                }
                return true;
            };

 

问题四:程序报异常:System.Exception: Selector invoked from objective-c on a managed object that has been GC'ed,则标识gc已经回收了对象但是runtime还在调用。下面列出一些基本的编码规则可以减少相应的问题

 

1) 只在ViewDidLoad事件中创建控件。Only create controls in ViewDidLoad()

2) 控件使用类变量进行引用。Only store these in class level vars

3) 使用evernthandler而不是内联delegate Use event handler methods rather than inline delegates???

4) 在ViewDidLoad事件之那个进行逻辑处理。In the ViewDidUnload do xyz...

posted @ 2012-06-08 17:05 sdhjl2000 阅读(...) 评论(...) 编辑 收藏