Xamarin 仅在 iOS 上对模型进行 SQLite 更新调用时崩溃

Xamarin Crash on iOS only on SQLite update call for model

仅在 iOS 上使用 SQLite PCL 进行更新时应用程序崩溃。在 Android 上运行良好。有人有什么想法吗?

我的 SQLite NuGet

在 App.SqliteConnection.Update(pAssetRecovery)

处崩溃
public static async Task Update(Models.Model_AssetRecovery pAssetRecovery)
    {
        try
        {
            await Task.Run(() => App.SqliteConnection.Update(pAssetRecovery));
        }
        catch (SystemException ex)
        {}

    }

正在保存的模型

    [Table("tblAssetRecovery")]
    public class Model_AssetRecovery : _Model_Base
    {
        [PrimaryKey, NotNull, Unique]
        public string strAssetRecoveryID { get; set; }
        public string strAssignmentID { get; set; }
        public string strAssetID { get; set; }
        public int intAssignmentIdentity { get; set; }
        public int intCurrentPage { get; set; }
        public int intRecoveryUsersID { get; set; }
        public string strDebtorAddressID { get; set; }
        public string strRecoveryAddress1 { get; set; }
        public string strRecoveryAddress2 { get; set; }
        public string strRecoveryCity { get; set; }
        public string strRecoveryZipcode { get; set; }
        public string strRecoveryLongitude { get; set; }
        public string strRecoveryLatitude { get; set; }
        public int intRecoveryStateID { get; set; }
        public int intRecoveryCountryID { get; set; }
        public string strRecoveryDate { get; set; }
        public TimeSpan tspanRecoveryTime { get; set; }
        public string strRecoveryNotificationAgency { get; set; }
        public string strRecoveryNotificationPhone { get; set; }
        public string strRecoveryNotificationDate { get; set; }
        public TimeSpan tspanRecoveryNotificationTime { get; set; }
        public string strRecoveryNotificationNote { get; set; }
        public string strRecoveryNotificaitonAddress1 { get; set; }
        public string strRecoveryNotificaitonAddress2 { get; set; }
        public string strRecoveryNotificaitonCity { get; set; }
        public string strRecoveryNotificaitonZipCode { get; set; }
        public string strDMVInfo { get; set; }
        public string strRecoveryNotificaitonCounty { get; set; }
        public int intRecoveryNotificationStateID { get; set; }
        public string strAssetRecoveryParagraph { get; set; }
        public int intTowDollyUsed { get; set; }
        public int intIsLPRRecovery { get; set; }
        public string strAssetColor { get; set; }
        public int intAssetYear { get; set; }
        public string strAssetMake { get; set; }
        public string strAssetModel { get; set; }
        public string strAssetVIN { get; set; }
        public string strAssetBodyStyle { get; set; }
        public int intRecoveryAddressSource { get; set; }
        public int intRecoveryAddressType { get; set; }
        public string strCounty { get; set; }
        public int intStorageLotID { get; set; }
        public int intKeysObtained { get; set; }
        public int intKeysPlanToObtain { get; set; }
        public int intKeysObtainedSource { get; set; }
        public int intOdometerReading { get; set; }
        public int intOdometerType { get; set; }
        public string strCompletionMessage { get; set; }
        public int intAccessToInterior { get; set; }
        public int intIsAssetDamaged { get; set; }
        public int intAirbagsDeployed { get; set; }
        public int? intVehicleLicenseStateID { get; set; }
        public string strPlateNumber { get; set; }
        public int intAssignmentType { get; set; }
        public int intAssignmentStatus { get; set; }
        public int intLPRProvider { get; set; }
        public int intCanYouRecordMileage { get; set; }


    }
}

iOS DI SQLiteHandler

class SQLite_iOS : ISQLiteConnection
    {
        public SQLiteConnection GetConnection()
        {
            try
            {
                var sqliteFilename = "MyApp.db3";
                string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); // Documents folder
                string libraryPath = Path.Combine(documentsPath, "..", "Library"); // Library folder
                var path = Path.Combine(libraryPath, sqliteFilename);
                // Create the connection
                var plat = new SQLite.Net.Platform.XamarinIOS.SQLitePlatformIOS();
                var conn = new SQLite.Net.SQLiteConnection(plat, path);
                // Return the database connection
                return conn;
            }
            catch (SystemException ex)
            {
                namespace.Classes.Helpers.Helper_ErrorHandling.SendErrorToServer(ex, "GetConnection_iOS", "GetConnection_iOS");
                //Device.BeginInvokeOnMainThread(() => App.iAppNavigation.GetErrorPage());
                return null;
            }
        }
    }

Visual Studio错误

2015-05-15 16:47:19.775 namespace[4678:182349] critical: Stacktrace:

2015-05-15 16:47:19.789 namespace[4678:182349] critical:   at <unknown> <0xffffffff>
2015-05-15 16:47:19.789 namespace[4678:182349] critical:   at (wrapper managed-to-native) SQLite.Net.Platform.XamarinIOS.SQLiteApiIOSInternal.sqlite3_prepare_v2 (intptr,string,int,intptr&,intptr) <IL 0x00028, 0xffffffff>
2015-05-15 16:47:19.789 namespace[4678:182349] critical:   at SQLite.Net.Platform.XamarinIOS.SQLiteApiIOS.Prepare2 (SQLite.Net.Interop.IDbHandle,string) <IL 0x0001c, 0x00190>
2015-05-15 16:47:19.790 namespace[4678:182349] critical:   at SQLite.Net.SQLiteCommand.Prepare () <IL 0x0001c, 0x000e5>
2015-05-15 16:47:19.790 namespace[4678:182349] critical:   at SQLite.Net.SQLiteCommand.ExecuteNonQuery () <IL 0x00017, 0x000db>
2015-05-15 16:47:19.790 namespace[4678:182349] critical:   at SQLite.Net.SQLiteConnection.Execute (string,object[]) <IL 
0x00044, 0x00214>
2015-05-15 16:47:19.790 namespace[4678:182349] critical:   at SQLite.Net.SQLiteConnection.Update (object,System.Type) <IL 0x00104, 0x00b58>
2015-05-15 16:47:19.791 namespace[4678:182349] critical:   at SQLite.Net.SQLiteConnection.Update (object) <IL 0x0000d, 0x000e2>
2015-05-15 16:47:19.791 namespace[4678:182349] critical:   at namespace.Classes.Helpers.SQLite.Helper_SQLite_AssetRecovery/<>c__DisplayClass9.<Update>b__7 () [0x00000] in d:\LocalRepository\namespace\namespace\namespace\Classes\Helpers\SQLite\Helper_SQLite_AssetRecovery.cs:32
2015-05-15 16:47:19.791 namespace[4678:182349] critical:   at System.Threading.Tasks.Task`1<int>.InnerInvoke () [0x00012] in /Users/builder/data/lanes/1503/6481535e/source/mono/external/referencesource/mscorlib/system/threading/Tasks/Future.cs:686
2015-05-15 16:47:19.791 namespace[4678:182349] critical:   at System.Threading
.Tasks.Task.Execute () [0x00016] in /Users/builder/data/lanes/1503/6481535e/source/mono/external/referencesource/mscorlib/system/threading/Tasks/Task.cs:2523
2015-05-15 16:47:19.792 namespace[4678:182349] critical:   at System.Threading.Tasks.Task.ExecutionContextCallback (object) [0x00007] in /Users
/builder/data/lanes/1503/6481535e/source/mono/external/referencesource/mscorlib/system/threading/Tasks/Task.cs:2887
2015-05-15 16:47:19.792 namespace[4678:182349] critical:   at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext,System.Threading.ContextCallback,object) [0x00027] in /Users/builder/data/lanes/1503/6481535e/source/mono/mcs/class/corlib/System.Threading/ExecutionContext.cs:242
2015-05-15 16:47:19.792 namespace[4678:182349] critical:   at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext,System.Threading.ContextCallback,object,bool) [0x00000] in /Users/builder/data/lanes/1503/6481535e/source/mono/mcs/class/corlib/System.Threading/ExecutionContext.cs:228
2015-05-15 16:47:19.793 namespace[4678:182349] critical:   at System.Threading.Tasks.Task.ExecuteWithThreadLocal (System.Threading.Tasks.Task&) [0x0005f] in /Users/builder/data/lanes/1503/6481535e/source/mono/external/referencesource/mscorlib/system/threading/
Tasks/Task.cs:2848
2015-05-15 16:47:19.793 namespace[4678:182349] critical:   at System.Threading.Tasks.Task.ExecuteEntry (bool) [0x0006f] in /Users/builder/data/lanes/1503/6481535e/source/mono/external/referencesource/mscorlib/system/threading/Tasks/Task.cs:2781
2015-05-15 16:47:19.793 namespace[4678:182349] critical:   at System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () [0x00000] in /Users/builder/data/lanes/1503/6481535e/source/mono/external/referencesource/mscorlib/system/threading/Tasks/Task.cs:2728
2015-05-15 16:47:19.794 namespace[4678:182349] critical:   at System.Threading.ThreadPool.<UnsafeQueueCustomWorkItem>m__0 (object) [0x00000] in /Users/builder/data/lanes/1503/6481535e/source/mono/mcs/class/corlib/System.Threading/ThreadPool.cs:258
2015-05-15 16:47:19.794 namespace[4678:182349] critical:   at (wrapper runtime-invoke) <Module>.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <IL 0x00062, 0xffffffff>
2015-05-15 16:47:19.794 namespace[4678:182349] critical: 
Native stacktrace:

2015-05-15 16:47:19.795 namespace[4678:182349] critical: 
=================================================================
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================

Activity日志

<entry>
    <record>1054</record>
    <time>2015/05/15 23:29:58.111</time>
    <type>Error</type>
    <source>Editor or Editor Extension</source>
    <description>System.InvalidCastException: Unable to cast object of type &apos;Xamarin.VisualStudio.Debugger.AD7DocumentContext&apos; to type &apos;Microsoft.VisualStudio.Debugger.Interop.IDebugDocumentContext2&apos;.&#x000D;&#x000A;   at System.StubHelpers.InterfaceMarshaler.ConvertToManaged(IntPtr pUnk, IntPtr itfMT, IntPtr classMT, Int32 flags)&#x000D;&#x000A;   at Microsoft.VisualStudio.Debugger.Interop.IDebugStackFrame2.GetDocumentContext(IDebugDocumentContext2&amp; ppCxt)&#x000D;&#x000A;   at Microsoft.VisualStudio.Debugger.Parallel.Common.DocumentContext.GetFileNameAndPath()&#x000D;&#x000A;   at Microsoft.VisualStudio.Debugger.Parallel.UI.ThreadMarkerGenerator.LocationMatchesTagger(DocumentContext location, MarkerTagger tagger)&#x000D;&#x000A;   at Microsoft.VisualStudio.Debugger.Parallel.UI.ThreadMarkerGenerator.&lt;&gt;c__DisplayClass1.&lt;GetMarkersForTagger&gt;b__0(ThreadMarker marker)&#x000D;&#x000A;   at System.Linq.Enumerable.WhereListIterator`1.MoveNext()&#x000D;&#x000A;   at Microsoft.VisualStudio.Debugger.Parallel.Extension.MarkerTagger.&lt;GenerateTagList&gt;d__a.MoveNext()&#x000D;&#x000A;   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)&#x000D;&#x000A;   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)&#x000D;&#x000A;   at Microsoft.VisualStudio.Debugger.Parallel.Extension.MarkerTagger..ctor(ITextBuffer buffer, ITextDocument document)&#x000D;&#x000A;   at Microsoft.VisualStudio.Debugger.Parallel.Extension.MarkerTaggerProvider.CreateTagger[T](ITextBuffer buffer)&#x000D;&#x000A;   at Microsoft.VisualStudio.Text.Tagging.Implementation.TagAggregator`1.GatherTaggers(ITextBuffer textBuffer)</description>
  </entry>
</activity>

我知道你的问题已经过去了很多时间,但这是我能够找到类似问题(比如我的)的少数几个地方之一,所以我只想分享在我的案例中解决它的方法。

问题:

我在使用来自不同线程的数据库连接的不同方法中遇到异常,这让我相信 iOS 中的 SQLite 由于某种原因不是线程安全的,例如 Android 和WinRT(我使用的是相同的代码,它有一些锁和互斥锁,但使用延迟查询的方法在锁释放后导致了问题)。

所以对我来说修复它的是在连接构造函数中使用额外的参数来启用 SQLite 的线程安全(或者至少我认为这是正在发生的事情:))

解决方法:

var connection = new SQLiteConnection(    
  new SQLite.Net.Platform.XamarinIOS.SQLitePlatformIOS(),
  sqliteFilename,
  openFlags: SQLiteOpenFlags.ReadWrite|SQLiteOpenFlags.FullMutex|SQLiteOpenFlags.Create,
  storeDateTimeAsTicks: true);

这里重要的是标志 - 我认为 FullMutex 在 iOS 中默认情况下不会打开,这与 Android 和 WinRT

不同

希望它对其他人有所帮助,祝大家编码愉快 ;)

尝试在工具 -> Nuget 包管理器下下载这个包 "SQLite.Net PLC",它对我有用

如果其他人在 iOS 上遇到此问题,这可能会对您有所帮助。

我正在使用 Xamarin Forms,我的项目在 Android 上工作正常,但在 iOS 上不工作。那是因为对于 iOS,bundle_green(这是 Microsoft.data.sqlite 的依赖项)使用了作为 iOS 本身一部分的 sqlite 库,并且该库(显然)是 NOT 以序列化为线程模式编译。

对于 Android,bundle_green 包含一个不同的 sqlite 库实例,而不是使用来自 Android 的实例,因为 Android N 不允许这样做了。此捆绑实例使用序列化线程模式编译。

您可以使用此代码段检查正在使用的 ThreadingMode

var result = SQLitePCL.raw.sqlite3_threadsafe();

string description = "";

switch (result)
{
    case 1:
        // Thread-safe. Lock statements not required.
        description = "Serialized";
        break;
    case 2:
        // Mutexing code is there, but mutexing on database connection and prepared statement objects is disabled.
        // Application is responsible for serializing access to database connections and prepared statements, so must use lock statements.
        description = "Multi-Threaded";
        break;
    default:
        // SQLite was compiled with mutexing code omitted. It is not safe to use SQLite concurrently from more than one thread.
        description = "Mutexing code omitted";
        break;
}

Console.log(description);

所以修复在你的 AppDelegate.cs 文件中添加这个 -

SQLitePCL.Batteries_V2.Init();
raw.sqlite3_shutdown();
raw.sqlite3_config(SQLitePCL.raw.SQLITE_CONFIG_SERIALIZED);
raw.sqlite3_initialize();

这样做是在运行时将 ThreadMode 设置为序列化,您应该停止收到 SIGSEGV 错误。