在CollectionView的UITextView中渲染动态HTML代码会引起问题

时间:2019-05-10 10:06:03

标签: c# ios xamarin xamarin.ios uicollectionview

我们正在开发消息传递应用程序,并且正在使用包含几种类型的单元格的collectionview。单元格具有不同的类型并具有动态大小,其中一个单元格应显示从Web服务器接收的具有多种颜色和格式的样式化文本。 单元格在第一个视图上正确显示了此信息,但滚动后,应用程序在HTML重新呈现时崩溃,并显示错误:

  

收到未处理的ObjectiveC异常:NSRangeException

我们基于此链接实现了collectionview UICollectionView insert cells above maintaining position (like Messages.app)

下面是代码:

我们尝试添加计算用于缓存的NSAttribute,但是由于它们另存为字符串,因此我们无法将它们恢复为NSAttribute

ChatCollectionViewSource.cs

[Export("collectionView:layout:sizeForItemAtIndexPath:"), CompilerGenerated]
public virtual CGSize GetSizeForItem(UICollectionView collectionView, UICollectionViewLayout layout, NSIndexPath indexPath)
{
    var msg = chatMessages[indexPath.Row];
    var estimatedFrame = new CGRect(0, 0, 220, 1000);

    if(msg.Message.IsHtml()){
        var ss = NSString ss = new NSString(msg.Message);
        var htmlAttributes = TextHelper.GetHtmlNSAttributes(ss);
        var estimatedFrame = TextHelper.GetEstimatedCGRectHtml(htmlAttributes); 
        return new CGSize(this.view.Frame.Width, estimatedFrame.Height + 24);
    }
    else {
        // return cgsize of nonhtml text cell
    }
}

public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
    var msg = chatMessages[indexPath.Row];
    var textCell = collectionView.DequeueReusableCell("message_cell_identifier", indexPath) as MessageCell;

    textCell.Layer.ShouldRasterize = true;
    textCell.Layer.RasterizationScale = UIScreen.MainScreen.Scale;

    var estimatedFrame = new CGRect(0, 0, 220, 1000);

    if (msg.Message.IsHTML()) // html
    {
        NSString ss = new NSString(msg.Message);

        NSAttributedString NSAttributes = null;
        NSAttributes = TextHelper.GetHtmlNSAttributes(ss);

        textCell.SetHTML(NSAttributes, msg.Date, msg.Id.ToString());
        textCell.NSAttributedString = NSAttributes;
    }
    else
    {
        textCell.SetText(msg, msg.Date);
        estimatedFrame = TextHelper.GetEstimatedCGRect(msg.Message); // get estimated frame
    }

    textCell.SetFrame(estimatedFrame, chatMessages[indexPath.Row].IsSend, this.view, msg);

    return textCell;
}   

MessageCell.cs

public void SetHTML(NSAttributedString NSAttributes, DateTime dateTime, string Id = null)
{
    //ChatTextView.TextStorage.BeginEditing();
    try
    {
        ChatTextView.TextColor = null;

        if (NSAttributes != null)
        {
            DispatchQueue.MainQueue.DispatchAsync(() =>
            {
                ChatTextView.AttributedText = new NSMutableAttributedString(NSAttributes);
            });
        }
    }
    catch (Exception exception)
    {
        Debug.WriteLine(exception);
    }}

TextHelper.cs

    public static NSAttributedString GetHtmlNSAttributes(NSString HTMLtext)
        {
            var HTMLStyle = "<style>.body{font-family: '-apple-system', 'GothamMedium'; font-size:13; color:rgb(179, 178, 178);}</style>";
            var text = HTMLStyle + "<div class='body'>" + HTMLtext + "</div>";
            var ns = (NSString)text;

            var myHtmlData = ns.Encode(NSStringEncoding.Unicode);

            var options = new NSAttributedStringDocumentAttributes
            {
                DocumentType = NSDocumentType.HTML
            };

            NSError error = new NSError();
            error = null;
            NSDictionary dict = new NSDictionary();
            dict = null;

            try
            {
                var attrString = new NSAttributedString(myHtmlData, options, out dict, ref error);

                return attrString;
            }
            catch (Exception ex)
            {
                Console.WriteLine(myHtmlData);
                Console.WriteLine(ex.Message);
                Console.WriteLine(options);
                return null;
                //throw ex;
            }
        }

这实际上很好用

我们正在尝试添加功能: 获取最近50条消息(无限滚动) 当用户滚动到列表顶部

ChatViewController.cs

#region scrolled to top observer
scrolledToTopObs = NSNotificationCenter.DefaultCenter.AddObserver((NSString)"scrolled_to_top",
async (notification) =>
{
    var moreMessages = await Static.DB.getChatsAsync(this.CaseId, this.UserType, ++page);

    if (moreMessages.Count == 0)
        return;

    list.InsertRange(0, moreMessages);

    Debug.WriteLine("items count in list: " + list.Count);

    // https://stackoverflow.com/questions/25548257/uicollectionview-insert-cells-above-maintaining-position-like-messages-app

    NSIndexPath[] insertedPaths = new NSIndexPath[moreMessages.Count];
    for (int i = 0; i < insertedPaths.Length; i++)
        insertedPaths[i] = NSIndexPath.FromItemSection(i, 0);

    DispatchQueue.MainQueue.DispatchAsync(() =>
    {

        var bottomOffset = ChatCollectionView.ContentSize.Height - ChatCollectionView.ContentOffset.Y;
        CATransaction.Begin();
        CATransaction.DisableActions = true;
        ChatCollectionView.PerformBatchUpdates(() =>
        {
            ChatCollectionView.InsertItems(insertedPaths);
        },
        (finished) =>
        {
            ChatCollectionView.SetContentOffset(new CGPoint(0, ChatCollectionView.ContentSize.Height - bottomOffset), false);
            CATransaction.Commit();
        });
    });
});

该崩溃报告在DispatchQueue.MainQueue.DispatchAsync()之后导致应用崩溃:

  

2019-05-10 12:10:3​​8.152 MyApp [1890:923892] Xamarin.iOS:已收到   未处理的ObjectiveC异常:NSRangeException *-[__ NSArrayM   objectAtIndexedSubscript:]:索引16超出范围[0 .. 15]   2019-05-10 12:10:3​​8.156 MyApp [1890:923892] ................................   NSAttributedString类型的HTMLString为null 2019-05-10 12:10:3​​8.163   MyApp [1890:923892]引发了Objective-C异常。名称:   NSRangeException原因:* -[__ NSArrayM objectAtIndexedSubscript:]:   索引16超出范围[0 .. 15]本机堆栈跟踪:0
  CoreFoundation 0x00000001bb829ebc +   252 1 libobjc.A.dylib 0x00000001ba9f9a50   objc_exception_throw + 56 2 CoreFoundation
  0x00000001bb7a1384 _CFArgv + 0 3 CoreFoundation
  0x00000001bb724b78 + 0 4 UIKitCore
  0x00000001e82d4f5c + 1836 5 UIKitCore
  0x00000001e82d69dc + 260 6 UIKitCore
  0x00000001e82d0d48 + 44 7 UIKitCore
  0x00000001e82b3d50 + 1648 8 UIKitCore
  0x00000001e82b3580 + 92 9基金会
  0x00000001bc2c9420 __NSFireDelayedPerform + 404 10 CoreFoundation
  0x00000001bb7ba718 + 28 11 CoreFoundation
  0x00000001bb7ba448 + 864 12 CoreFoundation
  0x00000001bb7b9c7c + 248 13 CoreFoundation
  0x00000001bb7b4b58 + 1880 14 CoreFoundation
  0x00000001bb7b40e0 CFRunLoopRunSpecific + 436 15 UIFoundation
  0x00000001c5e42368 + 1728 16 UIFoundation
  0x00000001c5e4533c + 28 17 UIFoundation
  0x00000001c5e923ec _NSReadAttributedStringFromURLOrData + 8120 18   UIFoundation 0x00000001c5e45278 +   136 19 MyApp 0x000000010318b498 MyApp   + 5911704 20 MyApp 0x0000000103143104 MyApp + 5615876 21 MyApp
  0x000000010314329c MyApp + 5616284 22 MyApp
  0x0000000102ca95f4 MyApp + 792052 23 MyApp
  0x0000000102c7594c MyApp + 579916 24 MyApp
  0x000000010305b598 MyApp + 4666776 25 Mono
  0x0000000105a38f08 mono_get_runtime_build_info + 1332 26 Mono
  0x0000000105add8a4 mono_runtime_invoke_checked + 152 27 Mono
  0x0000000105ae1214 mono_runtime_invoke + 160 28 MyApp
  0x0000000102c40e98 MyApp + 364184 29 MyApp
  0x0000000102c40af0 MyApp + 363248 30 UIKitCore
  0x00000001e82d53ac + 2940 31 UIKitCore
  0x00000001e82d69dc + 260 32 UIKitCore
  0x00000001e82d0830 + 224 33 UIKitCore
  0x00000001e82c9054 + 228 34 UIKitCore
  0x00000001e82ac2d4 + 10232 35 UIKitCore
  0x00000001e82b3f90 + 92 36 UIKitCore
  0x00000001e82b42c8 + 388 37 UIKitCore
  0x00000001e82b4124 + 96 38 UIKitCore
  0x00000001e82b40a8 + 84 39 UIKitCore
  0x00000001e82b3fe4 + 64 40 MyApp
  0x00000001031868f8 MyApp + 5892344 41 MyApp
  0x0000000103129e88 MyApp + 5512840 42 MyApp
  0x0000000102cc1878 MyApp + 891000 43 MyApp
  0x000000010315a830 MyApp + 5711920 44 MyApp
  0x0000000103194a7c MyApp + 5950076 45 libdispatch.dylib
  0x00000001bb262484 + 16 46 libdispatch.dylib
  0x00000001bb20e9a4 + 1068 47 CoreFoundation
  0x00000001bb7b9ce4 + 12 48 CoreFoundation
  0x00000001bb7b4bac + 1964 49 CoreFoundation
  0x00000001bb7b40e0 CFRunLoopRunSpecific + 436 2019-05-10 12:10:3​​8.163   MyApp [1890:923892] 50 GraphicsServices
  0x00000001bda2d584 GSEventRunModal + 100 51 UIKitCore
  0x00000001e89c8c00 UIApplicationMain + 212 52 MyApp
  0x00000001031914e4 MyApp + 5936356 53 MyApp
  0x000000010312798c MyApp + 5503372 54 MyApp
  0x000000010312794c MyApp + 5503308 55 MyApp
  0x0000000102c591c0 MyApp + 463296 56 MyApp
  0x000000010305b598 MyApp + 4666776 57 Mono
  0x0000000105a38f08 mono_get_runtime_build_info + 1332 58 Mono
  0x0000000105add8a4 mono_runtime_invoke_checked + 152 59 Mono
  0x0000000105ae3b54 mono_runtime_exec_main_checked + 120 60 Mono
  0x0000000105a16bfc mono_jit_exec + 316 61 MyApp
  0x000000010548777c _Z9__isctypeim + 56712 62 MyApp
  0x0000000102c590b8 MyApp + 463032 63 libdyld.dylib
  0x00000001bb272bb4 + 4

     

2019-05-10 12:10:3​​8.163 MyApp [1890:923892]   Foundation.NSAttributedStringDocumentAttributes到达顶部   collectionview 12:10:38 PM列表中的项目数:300 objc [1890]:   无效或过早释放的自动释放池0x1057f33c8。

     

本机崩溃报告

     

在执行本机代码时获得了SIGABRT。这通常表示   Mono运行时或使用的本机库之一中的致命错误   通过您的应用程序。

     

基本故障地址报告

     

本机指令指针周围的内存...

     

本机堆栈跟踪:

     

0x105a30fc8-   /private/var/containers/Bundle/Application/20685366-DEC9-4CB0-BA4E-3B41F073FEBD/MyApp.app/Frameworks/Mono.framework/Mono   :mono_dump_native_crash_info 0x105a270c8-   /private/var/containers/Bundle/Application/20685366-DEC9-4CB0-BA4E-3B41F073FEBD/MyApp.app/Frameworks/Mono.framework/Mono   :mono_handle_native_crash 0x1bb4359f0-   /usr/lib/system/libsystem_platform.dylib:0x1bb3b780c-   /usr/lib/system/libsystem_kernel.dylib:0x1bb3b77a8-   /usr/lib/system/libsystem_kernel.dylib:0x1ba9f94c4-   /usr/lib/libobjc.A.dylib:0x1ba9f941c-   /usr/lib/libobjc.A.dylib

0 个答案:

没有答案