首页 \ 问答 \ MFMessageComposeVIewController忽略它的委托,而不是它本身(MFMessageComposeVIewController is dismissing its delegate instead of itself)

MFMessageComposeVIewController忽略它的委托,而不是它本身(MFMessageComposeVIewController is dismissing its delegate instead of itself)

我有一个符合MFMessageComposeViewControllerDelegate协议的VC。

我用下面的代码成功地展示了这个视图控制器:

- (IBAction)textAction:(id)sender {
    if(![MFMessageComposeViewController canSendText])
    {
        UIAlertView *warningAlert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Your device doesn't support SMS!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [warningAlert show];
        return;
    }

    NSString *numberToCallOrText = self.phoneNumber;
    NSString *message = @"Test message";
    NSArray *recipients = [NSArray arrayWithObject:numberToCallOrText];
    MFMessageComposeViewController *messageController = [[MFMessageComposeViewController alloc] init];
    messageController.messageComposeDelegate = self;
    [messageController setRecipients:recipients];
    [messageController setBody:message];

    // Present message view controller on screen
    [self.view endEditing:YES];
    [self presentViewController:messageController animated:YES completion:nil];
}

另外,我正在处理完成结果,如下所示:

- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult) result
{
    switch (result) {
        case MessageComposeResultCancelled:
            NSLog(@"Canceled");
            break;

        case MessageComposeResultFailed:
        {
            NSLog(@"Failed");
            UIAlertView *warningAlert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Failed to send SMS!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [warningAlert show];
            break;
        }

        case MessageComposeResultSent:
            NSLog(@"sent");
            [self.navigationController popViewControllerAnimated:YES];
            break;

        default:
            break;
    }
    [controller.view endEditing:YES];
    [self.navigationController popViewControllerAnimated:YES];
//    [self dismissViewControllerAnimated:YES completion:nil];
//    [controller popToViewController:self animated:YES];
//    [controller dismissViewControllerAnimated:YES completion:nil];
}

三条注释掉的线是我尝试过的替代品。 发生的事情是MFMessageComposeViewController保留在屏幕上(虽然键盘被解除),但是委托从堆栈中弹出。 因此,当我再次点击取消时,我得到一个空引用错误。

这很奇怪,因为这个相同的实现在我的代码中的其他地方工作。 唯一的区别是我已经设置了要初始化的主体。

任何想法为什么错误的VC会在这里突然出现?

谢谢。

编辑 - 破坏的实现是在UITableViewController而不是UIView控制器...可能是什么导致了问题?


I have a VC that conforms to the MFMessageComposeViewControllerDelegate protocol.

I am successfully presenting this view controller with the following code:

- (IBAction)textAction:(id)sender {
    if(![MFMessageComposeViewController canSendText])
    {
        UIAlertView *warningAlert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Your device doesn't support SMS!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [warningAlert show];
        return;
    }

    NSString *numberToCallOrText = self.phoneNumber;
    NSString *message = @"Test message";
    NSArray *recipients = [NSArray arrayWithObject:numberToCallOrText];
    MFMessageComposeViewController *messageController = [[MFMessageComposeViewController alloc] init];
    messageController.messageComposeDelegate = self;
    [messageController setRecipients:recipients];
    [messageController setBody:message];

    // Present message view controller on screen
    [self.view endEditing:YES];
    [self presentViewController:messageController animated:YES completion:nil];
}

Additionally, I am handling the finish result like so:

- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult) result
{
    switch (result) {
        case MessageComposeResultCancelled:
            NSLog(@"Canceled");
            break;

        case MessageComposeResultFailed:
        {
            NSLog(@"Failed");
            UIAlertView *warningAlert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Failed to send SMS!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [warningAlert show];
            break;
        }

        case MessageComposeResultSent:
            NSLog(@"sent");
            [self.navigationController popViewControllerAnimated:YES];
            break;

        default:
            break;
    }
    [controller.view endEditing:YES];
    [self.navigationController popViewControllerAnimated:YES];
//    [self dismissViewControllerAnimated:YES completion:nil];
//    [controller popToViewController:self animated:YES];
//    [controller dismissViewControllerAnimated:YES completion:nil];
}

The three commented out lines are alternatives that I have tried. What's happening is that the MFMessageComposeViewController is remaining on the screen (though the keyboard is dismissed), but the delegate is being popped from the stack. Therefore, when I hit cancel again, I get a null reference error.

It's odd, because this same implementation works elsewhere in my code. The only difference is that I've set the body to be initialized.

Any ideas why the wrong VC is getting popped here?

Thanks.

Edit - The broken implementation is on a UITableViewController rather than UIView Controller... could that be what is causing the problem?


原文:https://stackoverflow.com/questions/40389457
更新时间:2022-11-05 16:11

最满意答案

我一开始努力让搜索字段在MVC风格的应用程序中工作。

我能够在你的sencha小提琴应用程序中使搜索字段工作。

在你的控制器中我做到了

Ext.define('Sencha.controller.Main', {
    extend: 'Ext.app.Controller',

    config: {
        refs: {
            main: 'mainpanel'
        },
        control: {
            '#list': {
                disclose: 'showDetail'
            },
            '#view':{
                activate:function(){
                    Ext.getCmp('list').add({
                        xtype:'toolbar',
                        docked:'top',
                        items:[{
                            xtype: 'searchfield',
                            itemId:'contact_search',
                            placeHolder: 'Search....',
                            listeners: {
                                scope: this,
                                clearicontap: this.onSearchClearIconTap,
                                keyup: this.onSearchKeyUp}
                        }]
                    })
                        }
            }
        }
    },

    showDetail: function(list, record) {
        this.getMain().push({
            xtype: 'recipedetail',
            title: record.fullName(),
            data: record.data
        })
            },  onSearchKeyUp: function(field) {
                //get the store and the value of the field
                var value = field.getValue(),
                    store = Ext.getCmp('list').getStore();

                //first clear any current filters on thes tore
                store.clearFilter();

                //check if a value is set first, as if it isnt we dont have to do anything
                if (value) {
                    //the user could have entered spaces, so we must split them so we can loop through them all
                    var searches = value.split(' '),
                        regexps = [],
                        i;

                    //loop them all
                    for (i = 0; i < searches.length; i++) {
                        //if it is nothing, continue
                        if (!searches[i]) continue;

                        //if found, create a new regular expression which is case insenstive
                        regexps.push(new RegExp(searches[i], 'i'));
                    }

                    //now filter the store by passing a method
                    //the passed method will be called for each record in the store
                    store.filter(function(record) {
                        var matched = [];

                        //loop through each of the regular expressions
                        for (i = 0; i < regexps.length; i++) {
                            var search = regexps[i],
                                didMatch = record.get('title').match(search);

                            //if it matched the first or last name, push it into the matches array
                            matched.push(didMatch);
                        }

                        //if nothing was found, return false (dont so in the store)
                        if (regexps.length > 1 && matched.indexOf(false) != -1) {
                            return false;
                        } else {
                            //else true true (show in the store)
                            return matched[0];
                        }
                    });
                }
            },

    /**
* Called when the user taps on the clear icon in the search field.
* It simply removes the filter form the store
*/
    onSearchClearIconTap: function() {
        //call the clearFilter method on the store instance
        this.getStore().clearFilter();
    }

});

然后在app.js中我向视口添加了一个ID

launch: function() {
        Ext.Viewport.add({
            id:'view',
            xtype: 'mainpanel'
        });
    }

我还在RecieptList.js中添加了一个ID

    xtype: 'recipelist',
    requires: ['Sencha.store.Recipes'],
    id:'list',
    config: {

可能不是最传统的解决方案,但它的工作原理。 很容易看出它们如何一起工作,希望有所帮助。


I struggled with getting the search field to work in an MVC style app at first.

I was able to make a search field work in your sencha fiddle app like this.

In your controller I did

Ext.define('Sencha.controller.Main', {
    extend: 'Ext.app.Controller',

    config: {
        refs: {
            main: 'mainpanel'
        },
        control: {
            '#list': {
                disclose: 'showDetail'
            },
            '#view':{
                activate:function(){
                    Ext.getCmp('list').add({
                        xtype:'toolbar',
                        docked:'top',
                        items:[{
                            xtype: 'searchfield',
                            itemId:'contact_search',
                            placeHolder: 'Search....',
                            listeners: {
                                scope: this,
                                clearicontap: this.onSearchClearIconTap,
                                keyup: this.onSearchKeyUp}
                        }]
                    })
                        }
            }
        }
    },

    showDetail: function(list, record) {
        this.getMain().push({
            xtype: 'recipedetail',
            title: record.fullName(),
            data: record.data
        })
            },  onSearchKeyUp: function(field) {
                //get the store and the value of the field
                var value = field.getValue(),
                    store = Ext.getCmp('list').getStore();

                //first clear any current filters on thes tore
                store.clearFilter();

                //check if a value is set first, as if it isnt we dont have to do anything
                if (value) {
                    //the user could have entered spaces, so we must split them so we can loop through them all
                    var searches = value.split(' '),
                        regexps = [],
                        i;

                    //loop them all
                    for (i = 0; i < searches.length; i++) {
                        //if it is nothing, continue
                        if (!searches[i]) continue;

                        //if found, create a new regular expression which is case insenstive
                        regexps.push(new RegExp(searches[i], 'i'));
                    }

                    //now filter the store by passing a method
                    //the passed method will be called for each record in the store
                    store.filter(function(record) {
                        var matched = [];

                        //loop through each of the regular expressions
                        for (i = 0; i < regexps.length; i++) {
                            var search = regexps[i],
                                didMatch = record.get('title').match(search);

                            //if it matched the first or last name, push it into the matches array
                            matched.push(didMatch);
                        }

                        //if nothing was found, return false (dont so in the store)
                        if (regexps.length > 1 && matched.indexOf(false) != -1) {
                            return false;
                        } else {
                            //else true true (show in the store)
                            return matched[0];
                        }
                    });
                }
            },

    /**
* Called when the user taps on the clear icon in the search field.
* It simply removes the filter form the store
*/
    onSearchClearIconTap: function() {
        //call the clearFilter method on the store instance
        this.getStore().clearFilter();
    }

});

And then in the app.js I added an ID to the viewport

launch: function() {
        Ext.Viewport.add({
            id:'view',
            xtype: 'mainpanel'
        });
    }

I also added an ID to the RecieptList.js

    xtype: 'recipelist',
    requires: ['Sencha.store.Recipes'],
    id:'list',
    config: {

Might not be the most conventional solution but it works. It is pretty easy to see how it all works together, hope that helps.

相关问答

更多

最新问答

更多
  • 在ios 7中的UITableView部分周围绘制边界线(draw borderline around UITableView section in ios 7)
  • Java中的不可变类(Immutable class in Java)
  • 寻求多次出现的表达式(Seeking for more than one occurrence of an expression)
  • linux只知道文件名,不知道在哪个目录,怎么找到文件所在目录
  • Actionscript:检查字符串是否包含域或子域(Actionscript: check if string contains domain or subdomain)
  • 懒惰地初始化AutoMapper(Lazily initializing AutoMapper)
  • 使用hasclass为多个div与一个按钮问题(using hasclass for multiple divs with one button Problems)
  • Windows Phone 7:检查资源是否存在(Windows Phone 7: Check If Resource Exists)
  • EXCEL VBA 基础教程下载
  • RoR - 邮件中的动态主体(部分)(RoR - Dynamic body (part) in mailer)
  • 无法在Google Script中返回2D数组?(Can not return 2D Array in Google Script?)
  • JAVA环境变量的设置和对path , classpth ,java_home设置作用和目的?
  • mysql 关于分组查询、时间条件查询
  • 如何使用PowerShell匹配运算符(How to use the PowerShell match operator)
  • Effective C ++,第三版:重载const函数(Effective C++, Third edition: Overloading const function)
  • 如何用DELPHI动态建立MYSQL的数据库和表? 请示出源代码。谢谢!
  • 带有简单redis应用程序的Node.js抛出“未处理的错误”(Node.js with simple redis application throwing 'unhandled error')
  • 使用前端框架带来哪些好处,相对于使用jquery
  • Ruby将字符串($ 100.99)转换为float或BigDecimal(Ruby convert string ($100.99) to float or BigDecimal)
  • 高考完可以去做些什么?注意什么?
  • 如何声明放在main之后的类模板?(How do I declare a class template that is placed after the main?)
  • 如何使用XSLT基于兄弟姐妹对元素进行分组(How to group elements based on their siblings using XSLT)
  • 在wordpress中的所有页面的标志(Logo in all pages in wordpress)
  • R:使用rollapply对列组进行求和的问题(R: Problems using rollapply to sum groups of columns)
  • Allauth不会保存其他字段(Allauth will not save additional fields)
  • python中使用sys模块中sys.exit()好像不能退出?
  • 将Int拆分为3个字节并返回C语言(Splitting an Int to 3 bytes and back in C)
  • 在SD / MMC中启用DDR会导致问题吗?(Enabling DDR in SD/MMC causes problems? CMD 11 gives a response but the voltage switch wont complete)
  • sed没有按预期工作,从字符串中间删除特殊字符(sed not working as expected, removing special character from middle of string)
  • 如何将字符串转换为Elixir中的函数(how to convert a string to a function in Elixir)