Рендеринг динамического HTML-кода в UITextView в CollectionView делает проблемы - PullRequest
2 голосов
/ 10 мая 2019

Мы разрабатываем приложение для обмена сообщениями и используем представление коллекции, которое содержит несколько типов ячеек.Ячейки имеют разные типы с динамическими размерами, одна из ячеек должна отображать стилизованный текст с многоцветными цветами и форматами, полученными от веб-сервера.Ячейка показывает это правильно при первом просмотре, но после прокрутки происходит сбой приложения при повторном рендеринге HTML с ошибкой:

Получено необработанное исключение ObjectiveC: NSRangeException

Мы реализовали наше представление коллекциина основе этой ссылки UICollectionView вставляет ячейки выше поддерживающей позиции (например, Messages.app)

Ниже приведен код:

Мы попытались добавить NSAttribute s, вычисленные ккэш, но мы не можем получить их обратно как NSAttribute s, поскольку они сохраняются в виде строк.

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: 38.152 MyApp [1890: 923892] Xamarin.iOS: получено необработанное исключение ObjectiveC: NSRangeException * - [__ NSArrayM objectAtIndexedSubscript:]: индекс 16 за пределами [0 .. 15] 2019-05-10 12: 10: 38.156 MyApp [1890: 923892]....................... HTMLString типа NSAttributedString имеет значение null 2019-05-10 12: 10: 38.163 MyApp [1890: 923892] Сгенерировано исключение Objective C.Имя: NSRangeException Причина: * - [__ NSArrayM objectAtIndexedSubscript:]: индекс 16 за пределами [0 .. 15] Собственная трассировка стека: 0
CoreFoundation 0x00000001bb829ebc + 252 1 libobjc.A.dylib 0x00000001bajf_f_99* тысячу сорок-шесть * 0x00000001bb7a1384 _CFArgv + 0 3 CoreFoundation * 1 047 * 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 * 1 058* 0x00000001bb7b40e0 CFRunLoopRunSpecific + 436 15 UIFoundation
0x00000001c5e42368 + 1728 16 UIFoundation
0x00000001c5e4533c + 28 17 UIFoundatioп * +1061 * 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 Моно * +1066 * 0x0000000105a38f08 mono_get_runtime_build_info + тысячу триста тридцать-две 26 Моно
0x0000000105add8a4 mono_runtime_invoke_checked + 152 27 Моно
0x0000000105ae1214 mono_runtime_invoke + 160 28 MyApp * 1 069 * 0x0000000102c40e98 MyApp + 364184 29 MyApp
0x0000000102c40af0 MyApp + 363248 30 UIKitCore
0x00000001e82d53ac + 2940 31 UIKitCore * 1 072 * 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: 38.163 MyApp [1890: 923892] 50 графических сервисов
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: 38.163 MyApp [1890: 923892] Foundation.NSAttributedStringDocumentAttributes достиг вершины Кол-во просмотров 12:10:38 Количество элементов в списке: 300 объектов [1890]: Неверный или преждевременно освобожденный пул авто-релиза 0x1057f33c8.

Собственные отчеты о сбоях

Получил SIGABRT при выполнении собственного кода. Это обычно указывает на фатальная ошибка в моно среде выполнения или в одной из собственных библиотек по вашему заявлению.

Базовая отчетность об отказах

Память вокруг родного указателя инструкций ...

Собственная трассировка стека:

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

...