تحتوي برامج تشغيل MACOS الخاصة بـ WACOM على الخيزران و Graphire و Intuos 1 و 2 و 3 و Cintiq 1st Gen على أخطاء تتسبب في فشلهم تمامًا في بدء MacOS 10.15 كاتالينا والإصدارات اللاحقة (بما في ذلك 11 Big Sur و 12 Monterey). لا ينطبق هذا على برنامج تشغيل Windows ، أو على برامج التشغيل لأجهزة اللوحات الأحدث.
عندما تحاول فتح جزء تفضيل WACOM باستخدام جهاز لوحي من الخيزران ، ستحصل على رسالة خطأ تقول "في انتظار المزامنة" ، ثم أخيرًا "هناك مشكلة مع برنامج تشغيل اللوحي. يرجى إعادة تشغيل نظامك. أو تحديث برنامج التشغيل ". بالنسبة إلى جهاز الكمبيوتر اللوحي INTUOS 3 أو CINTIQ الأول ، سيتم فتح جزء التفضيل ، ولكن النقر على أي شيء سيؤدي إلى تعطله مع الرسالة "كان هناك خطأ في تفضيلات Wacom Tablet". بالنسبة إلى أقراص Graphire و Intuos 1 & 2 ، لم يتمكن مثبت برنامج التشغيل على Catalina.
لحسن الحظ ، تمكنت من تعقب المشكلات وقد قمت بتصحيح برامج التشغيل لإصلاحها!
يدعم برنامج تشغيل الخيزران الثابتة (v5.3.7-6) هذه الأجهزة اللوحية:
يدعم برنامج تشغيل Graphire 1 و 2 و INTUOS 1 و 2 (v6.1.6-4) هذه الأجهزة اللوحية:
يدعم برنامج تشغيل Graphire 3 الثابت (v5.2.6-5) هذه الأجهزة اللوحية:
يدعم برنامج تشغيل Graphire 4 الثابت (v5.3.0-3) هذه الأجهزة اللوحية:
ويدعم برنامج Intuos 3 و CINTIQ الثابت (V6.3.15-3) هذه الأجهزة اللوحية:
بالنسبة إلى Intuos 4 ، ليس هناك حاجة إلى إصلاحي. يمكنك استخدام برنامج التشغيل الرسمي لـ WACOM V6.3.41-2 بدلاً من ذلك.
؟ تعليمات اللغة الإنجليزية المبسطة
؟ / ؟؟ instruções em português
؟ 日本語で表示
؟ инетруияمس
؟ instrucciones en español
؟ Instrukcja Po Polsku
؟ تعليمات en français
قم بتنزيل المثبت الصحيح لجهازك اللوحي هنا وانقر فوقه بشكل مزدوج لتشغيله ، وسيؤدي ذلك إلى تثبيت الإصدار الثابت من برنامج تشغيل Wacom:
إذا تلقيت رسالة خطأ مفادها أن جهاز Mac يسمح فقط بتثبيت التطبيقات من متجر التطبيقات ، ثم انقر بزر الماوس الأيمن فوقه وانقر فوق "فتح" بدلاً من ذلك.
بعد التثبيت ، اتبع الإرشادات الواردة في القسم التالي لإصلاح أذونات الجهاز اللوحي.
المس نصيحة القلم الخاصة بك إلى جهازك اللوحي ، ويجب أن يطلب منك زيارة تفضيلات النظام> الأمان والخصوصية> علامة تبويب الخصوصية لمنح أذونات الكمبيوتر اللوحي.
في صفحة إمكانية الوصول ، انقر فوق القفل لإلغاء قفل الصفحة ، ثم ابحث عن أي إدخالات PenTabletDriver TabletDriver WacomTabletDriver WacomTabletSpringboard التي تراها في القائمة. افعل الشيء نفسه على صفحة مراقبة الإدخال.
إذا كان جهازك اللوحي يدعم اللمس ، فلمس الجهاز اللوحي بإصبعك ، فيجب أن يطالبك مرة أخرى بمنح الأذونات. في صفحة إمكانية الوصول ، قم بتعيين دخول ConsumerTouchDriver أو دخول WacomTouchDriver .
مع بعض الأجهزة اللوحية ، قد يظهر برنامج التشغيل فقط على صفحة مراقبة الإدخال ، وقد تحتاج إلى إعادة تشغيل مرة ثانية حتى تظهر على صفحة إمكانية الوصول أيضًا.
من المحتمل أن يكون لديك أذونات تركت من سائق الكمبيوتر اللوحي السابق ، وهذه الإدخالات التي لا معنى لها يجب إزالتها مثل ذلك:
في صفحة "إمكانية الوصول" للأمن والخصوصية ، ابحث عن أي شيء يتعلق بـ WACOM في القائمة (مثل PenTabletDriver و WacomTabletDriver و TabletDriver و ConsumerTouchDriver و WacomTabletSpringboard و WacomTouchDriver ) وتحديدها ، وانقر على زر ناقصها. انتقل إلى "صفحة مراقبة الإدخال" وافعل الشيء نفسه هناك.
الآن إما إعادة تشغيل جهاز الكمبيوتر الخاص بك ، أو قم بتشغيل هذين الأمرين في المحطة ، لإعادة تحميل برنامج تشغيل الكمبيوتر اللوحي. للأقراص الخيزران والرسوم البيانية 3 و 4:
launchctl unload /Library/LaunchAgents/com.wacom.pentablet.plist
launchctl load -w /Library/LaunchAgents/com.wacom.pentablet.plist
لأقراص Graphire 1 و 2 و Intuos و Cintiq:
launchctl unload /Library/LaunchAgents/com.wacom.wacomtablet.plist
launchctl load -w /Library/LaunchAgents/com.wacom.wacomtablet.plist
يجب أن يعيد ذلك المطالبات التي تطلب منك إضافة أذونات ، لذا ابدأ الآن الإرشادات الواردة في هذا القسم مرة أخرى.
بالنسبة لعدد قليل من الأشخاص ، لا يظهر برنامج تشغيل Wacom أبدًا في قائمة مراقبة المدخلات لهم. لإصلاح هذا ، افتح أولاً تطبيق "Terminal" والصق هذا الخط واضغط على Enter للتأكد من تمكين خدمة WACOM:
للأقراص الخيزران والرسوم البيانية 3 و 4:
launchctl load -w /Library/LaunchAgents/com.wacom.pentablet.plist
لأقراص Graphire 1 و 2 و Intuos و Cintiq:
launchctl load -w /Library/LaunchAgents/com.wacom.wacomtablet.plist
إذا لم يؤدي ذلك إلى أن يطلب منك إضافة أذونات مراقبة الإدخال عند محاولة استخدام الجهاز اللوحي ، فيمكنك إضافته يدويًا بدلاً من ذلك.
في Finder ، انقر فوق Go -> انتقل إلى المجلد ، وقم بصق هذا المسار هناك وانقر فوق "موافق":
/Library/Application Support/Tablet/
في هناك ، يجب أن ترى ملف "PentableTdriver" (Bamboo) أو "PentableTsPringboard" (Graphire 3 & 4) أو "WacomTableTsPringboard" (Graphire 1 & 2 ، Intuos ، Cintiq).
قم بإلغاء تأمين صفحة مراقبة الإدخال ، ثم اسحب ملف PentableTdriver / PentableTspringboard / WacomTableTsPringboard على إضافته لإضافته إلى القائمة ، وتأكد من أنه تم وضع علامة عليه. الآن أعد تشغيل جهاز الكمبيوتر الخاص بك ، وعندما تحاول استخدام الجهاز اللوحي ، يجب أن يطالبك بتخصيصه في صفحة إمكانية الوصول أيضًا ، وبعد ذلك يجب أن تبدأ العمل.
تأكد من أنك لا تزال لديك أحدث برنامج تشغيل WACOM مثبت للغاية. استخدم "Wacom Utility"/ "Tablet Utility" لإلغاء تثبيت جميع برامج تشغيل Wacom بالكامل (بدلاً من سحبها إلى القمامة) ، ثم قم بتثبيت برنامج التشغيل الخاص بي مرة أخرى.
يمكن أن تمنع التفضيلات الفاسدة الأشياء من العمل ، خاصة إذا قمت بتثبيت مجموعة من إصدارات السائقين المختلفة أثناء محاولة جعل الأشياء تعمل. استخدم الأداة المساعدة WACOM لإعادة ضبط تفضيلاتك ، وإعادة التشغيل ، ومحاولة استخدام الجهاز اللوحي مرة أخرى.
إذا كنت قد استمتعت بإعادة الجهاز اللوحي الخاص بك ، فيرجى التفكير في إرسال نصيحة لي!
هذا سيساعدني على تمويلي ومواصلة تطوير هذه المحركات الثابتة.
تطلق PentableTdriver سائقين فرعيين للقيام بالعمل من أجل ذلك ، مستهلكات المسلح والكمبيوتر اللوحي. للعثور على هؤلاء برامج التشغيل ضمن مجلد الموارد الخاص بها ، يطلق على هذه الوظيفة في النهاية لاستخراج مسار من عنوان URL:
CFString * MacPaths::PathFromURL (CFURL *url)
{
CFString *path;
path = _objc_retainAutoreleasedReturnValue (url-> path ());
_objc_release (path); /* Whoops, path is destroyed here! */
return path; /* Now returning a free'd path */
}سامحني لإعادة صياغة الكود الهدف الأصلي C كـ C ++ ، أنا لا أتحدث OBJC!
عندما ينشئ CFURL المسار ، يبدأ عدد المرجع في 1. إنه يصطف على انخفاض عدد المرجع في وقت لاحق عن طريق استدعاء autorelease() عليه ، ثم يعيده إلى برنامج تشغيل Wacom. هذه الدعوة إلى autorelease تتزايد مع مكالمة Wacom's retainAutoreleasedReturnValue() ، وهكذا يترك عدد مرجع المسار دون مساس ، في 1.
ولكن الآن يقوم برنامج تشغيل WACOM باستدعاء _objc_release() على المسار. هذا يقلل من عدد المرجع إلى 0 ، ويتم تحرير المسار على الفور!
يتم استخدام هذا المسار المحرر أثناء إطلاق السائق الفرعي ، والذي يمكن أن يؤدي إلى segfault في ProcessUtils::LaunchApplicationWithBundleID() . هذا يقتل السائق.
الإصلاح هو تغيير بايت واحد يحل محل المكالمة إلى _objc_release() في PathFromURL إلى مكالمة إلى _objc_retain() . هذا يمنع المسار من إطلاق سراحه قبل استخدامه ، والذي يعالج segfault.
يحتوي estrultourchedriver أيضًا على هذا الخطأ نفسه ، والتصحيح هو نفسه هناك.
يحتاج كل من سائق القلم وسائق اللمس إلى إصلاحات لمنعهم من الانهيار عند إجراء لفتة متعددة اللمس ، أو يتم استخدام حلقة التمرير للتكبير.
عند تنفيذ إيماءة ، تكون وظيفة CMacHIDGestureEventOSX1010::PostGesture مسؤولة عن إرسال هذه الإيماءة إلى نظام التشغيل:
void CMacHIDGestureEventOSX1010::PostGesture (EIOHIDEventType gestureType_I, int32_t eventDirAmount)
{
__CFDataOSX1010 *eventStructure;
if (gestureType_I == 61 /* kCGHIDEventTypeGestureStarted */ ) {
this -> eventPhase = 1 /* kCGSGesturePhaseBegan */ ;
} else {
this -> eventPhase = 4 /* kCGSGesturePhaseEnded */ ;
(**(code **)(*( long *) this + 0x18 ))( 0 , this ,( uint32_t ) eventDirAmount);
}
eventStructure = (__CFDataOSX1010 *) _CGEventCreate ( 0 ); // Dubious
_CGEventSetType (eventStructure, 29 /* kCGSEventGesture */ );
eventStructure-> eventSubType = gestureType_I; // Relies on the exact memory layout of CGEvent (!)
eventStructure-> eventDirAmount = eventDirAmount; // Ditto
_CGEventPost ( 0 , eventStructure);
_CFRelease (eventStructure);
} لاحظ كيف يتم إلقاء النتيجة من cgeventcreate على هيكل؟ من المفترض أن يكون CGEVENT نوعًا غير شفاف ، وليس من المفترض أن تعرف البرامج أو تعتمد على تصميمها ، حيث يتغير هيكله من إصدار OS إلى إصدار OS ، ولكن هنا يتم إلقاؤه على هيكل بحيث يمكن لـ eventSubType و eventDirAmount Fields يتم تعيينها مباشرة. يسبب هذان الكتابة فسادًا كبيرًا على كاتالينا ويؤدي إلى تحطم ، لأن تخطيط CGEvent قد تغير منذ سييرا!
تتمثل الطريقة المناسبة لتخزين القيم في حدث ما في استخدام API CGEVENTETETENTETEGERValueField ، والتي تتيح لك الرجوع إلى حقول CGEVENT بواسطة معرف منطقي بدلاً من وضعها في الذاكرة. إذن ما هي معرفات الحقل المكافئة للثانيين أن سائق Wacom يحتاج إلى صنعه؟
لقد قمت بفك إطار عمل MacOS Sierra ، الذي يحتوي على تنفيذ CGEventSetIntegerValueField ، لمعرفة ما كان يجب أن يكون عليه الهوية لتلك الحقول. يبدو أنه يمكن كتابة eventSubType بواسطة معرف الحقل 110 ، ويمكن كتابة eventDirAmount بواسطة ID 115. لكن معرفات الحقل هذه لا يمكن العثور عليها في وثائق Apple ، وهو ما يفسر لماذا لم يستطع Wacom استخدامها!
فعلت بعض googling واكتشفت أن هذه الحقول غير موثقة لأنها جزء من API الخاص من Apple. يكشف رأس WebKit هذا عن أسمائهم:
kCGEventGestureHIDType = 110
kCGEventGestureSwipeValue = 115
kCGEventGesturePhase = 132
وتلك حقول واجهة برمجة التطبيقات الخاصة مستقرة من سييرا على طول الطريق إلى بيج سور! الآن وبعد أن عرفنا ذلك ، يمكن استبدال هذه المهامين في EventStructure بهذه المكالمات ، ويتم القضاء على حوادث السائق:
_CGEventSetIntegerValueField (eventStructure, 110 /* kCGEventGestureHIDType */ , gestureType_I);
_CGEventSetIntegerValueField (eventStructure, 115 /* kCGEventGestureSwipeValue */ , eventDirAmount);النسخة العائمة من Postgesture لديها نفس المشكلة:
void CMacHIDGestureEventOSX1010::PostGesture (EIOHIDEventType eventSubType, float dirAmount)
{
__CFDataOSX1010 *eventStructure;
eventStructure = (__CFDataOSX1010 *) _CGEventCreate ( 0 );
_CGEventSetType (eventStructure, 29 /* kCGSEventGesture */ );
eventStructure-> eventSubType = eventSubType; // !
eventStructure-> eventDirAmount = reinterpret_cast < int32_t &>(dirAmount); // !
eventStructure-> eventState = this -> eventPhase ; // !
if ( this -> eventPhase == 1 /* kCGSGesturePhaseBegan */ ) {
this -> eventPhase = 2 /* kCGSGesturePhaseChanged */ ;
}
_CGEventSetLocation (eventStructure, GetMouseLocationInScreenCoordinates ());
_CGEventPost ( 0 , eventStructure);
_CFRelease (eventStructure);
}ويمكننا تصحيحه مثل:
_CGEventSetIntegerValueField (eventStructure, 110 /* kCGEventGestureHIDType */ , gestureType_I);
_CGEventSetIntegerValueField (eventStructure, 115 /* kCGEventGestureSwipeValue */ , reinterpret_cast < int32_t &>(dirAmount));
_CGEventSetIntegerValueField (eventStructure, 132 /* kCGEventGesturePhase */ , this ->eventPhase); في جزء تفضيل WACOM ، يقع WACOM ضحية Apple Bug 8746551. منذ MacOS Catalina ، يكسر جزء التفضيل بشكل فعال تشغيل NSApp->mainWindow من خلال السماح لأي نوع من النافذة ليصبح النافذة النشطة ، وحتى الأوراق ، والتي كانت مستحيلة في الإصدارات السابقة من الإصدارات السابقة MACOS وفي التطبيقات المستقلة (في الإصدارات السابقة فقط ، ستصبح نافذة التفضيلات الرئيسية الفعلية mainWindow ).
عندما تكون ورقة مشروط مفتوحة ، ويريد المستخدم فتح ورقة جديدة ، يجب إغلاق الورقة الأصلية أولاً. لكن حشرة Apple تتسبب في فحص Wacom لمعرفة ما إذا كانت هناك ورقة مفتوحة حاليًا للفشل ، لأنه عندما تتحقق لمعرفة ما إذا كانت ورقة متصلة بالمواد mainWindow ، فإنها تنتهي بدلاً من ذلك إلى التحقق من ورقة متصلة بالورقة الحالية ، والتي تحتوي على غير مفهوم بشكل غير مفهوم تصبح mainWindow . هذا يؤدي إلى حادث تحطم (على سبيل المثال في إعدادات تعيين القلم).
لقد قمت بتصحيح الوصول إلى mainWindow بحيث يتم تخزين القيمة الأولى التي يتم قراءتها بعد ذلك ، طالما أن القيمة الأولية معقولة ، لا يتم كسرها بعد تحديث mainWindow للإشارة إلى الورقة الأولى (انظر PenTablet.prefpane.newcode.asm ).
يحتوي برنامج تشغيل Intuos 3 و Cintiq على خطأ في جزء التفضيل الذي يتسبب في تعطله بمجرد النقر فوق عنصر.
واحدة من الميزات الرئيسية لجهاز واجهة المستخدم لجهاز التفضيل هي قوائم الرموز التي تمثل الأجهزة اللوحية والأدوات والتطبيقات التي يمكنك تكوينها. يستخدم التحكم في قائمة الأيقونات وظيفة كهذه لإرسال الأحداث (مثل النقرات) إلى أطفالها:
void WTCCPLIconList::action:(ID event, SEL param_2, ID param_3) {
int selectedIndex;
ID target;
ID action;
target = _objc_retainAutoreleasedReturnValue (event-> target ());
action = event-> action ();
selectedIndex = event-> selectedIndex ();
event-> scrollIndexToVisible (selectedIndex);
if ((target != 0 ) && (action != 0 )) {
code* handler = target-> methodForSelector (action);
Object *result = handler (target, action, event);
result = _objc_retainAutoreleasedReturnValue (result); // (!)
_objc_release (result); // (!)
}
event-> updateButtonStates ();
_objc_release (target);
} تكمن المشكلة في هذا الرمز في أنه يتطلب وظيفة handler() لإرجاع كائن ، والذي يحتفظ بعد ذلك () والإصدارات (). ولكن إحدى وظائف المعالج التي سيتم تسميتها هي OEventDispatcher_Professional::listClickAction() ، وهذه الوظيفة هي وظيفة void (مع عدم وجود قيمة إرجاع محددة جيدًا)!
لذلك action:() ينتهي الاتصال retain() release() على مؤشر القمامة ، والذي يسبب segfault.
التصحيح هنا سهل - يتم حذف زوج غير مجدي من مكالمات retain() release() . نفس الخطأ موجود في ONumberTextField::textDidChange: ، مع نفس الإصلاح.
هناك مشكلة أخرى مع هذا السائق. إذا ، أثناء محاولة جعل جهازك اللوحي يعمل ، تقوم بتثبيت أحدث برنامج تشغيل WACOM (لا يدعم Intuos 3) بطريق الخطأ ، فإنه يكتب ملف تفضيلات أحدث تنسيق سوف يعطل برنامج Intuos 3 القديم عند محاولة القراءة. وهذا الموقف لا يحل نفسه ، يتعين على المستخدم استخدام الأداة المساعدة لـ WACOM يدويًا لحذف تفضيلات الكمبيوتر اللوحي من أجل إصلاحه.
هذا أمر غريب لأن ملف التفضيل يتضمن رقم إصدار مصمم لتجنب هذا الموقف بالذات. يستخدم برنامج التشغيل القديم الإصدار 5 ، وأحدث برنامج تشغيل يستخدم الإصدار 6:
< ImportFileVersion type = " integer " >6</ ImportFileVersion >ويتحقق رمز برنامج التشغيل صراحةً عن رقم الإصدار هذا ويجب إحباطه عندما يكون جديدًا جدًا:
CTabletDriver::ReadSettings (basic_string settingsFilename, ...)
{
basic_string settingsFileContent;
CSettingsMap settingsMap;
...
ReadFromXMLFile (settingsMap, settingsFilename, settingsFileContent);
SettingsMigration *migration = SettingsMigration::MigratePen (settingsMap);
if (migration != nullptr ) {
int fileVersion = settingsMap. IntegerForKeyWithDefault ( " ImportFileVersion " , - 1 )
if (fileVersion < 1 ) {
// Report error
} else if (fileVersion <= this -> supportedVersion ) {
// Accept the loaded settings
} else {
// Report error: Settings are too new
}
}
...
} لكن السائق لا يجهض أبدًا ، بدلاً من ذلك يتعطل أثناء محاولة تحميل التفضيلات. إذن ما الخطأ هنا؟ السر يكمن داخل وظيفة MigratePen() . تم تصميم هذه الوظيفة لترقية ملفات الإعدادات الأقدم إلى الإصدار الحالي ، ولكن للأسف في العملية ، فإنها تكتب بشكل غير مشروط عملية ImportFileVersion مع الإصدار الحالي (5)! هذا يترك CTabletDriver::ReadSettings() غير قادر على اكتشاف أن الإعدادات جديدة جدًا بحيث لا يمكن تحليلها.
لحل هذا ، قمت بتعزيز رمز اكتشاف الإصدار غير صالح من MigratePen() :
if (settingsVersion < 1 ) {
// Report invalid settings version and return NULL
} لجعلها:
if (settingsVersion < 1 || settingsVersion > 5 ) {
// Report invalid settings version and return NULL
} حتى الآن إذا كانت التفضيلات جديدة جدًا ، فلن تحاول MigratePen() ترقيتها ، وسوف تخطي ReadSettings() بشكل نظيف تحميل التفضيلات. يؤدي هذا إلى البقاء التفضيلات في حالاتها الافتراضية ، وإذا قام المستخدم بتحرير الإعدادات باستخدام جزء التفضيل ، فيجب كتابة الإعدادات بشكل نظيف.
إن مثبتات برامج تشغيل Graphire هي شكل قديم لم يعد كاتالينا يدعمه ، لذلك اضطررت إلى إعادة بنائها تمامًا.
اعتمد جزء تفضيلات Graphire بشكل غير صحيح على رموز خاصة من مكتبة MacOS القياسية التي لم تعد موجودة في كاتالينا ، لذلك لم يعد بإمكانها البدء.
على سبيل المثال ، يتم استدعاء وظيفة Wacom's nsnibwakingoverride :: owakefromnib () أثناء تخلص من واجهة المستخدم الرسومية ، وتضيف التحكم في واجهة المستخدم الرسومية المحملة إلى الخريطة بحيث يمكن الوصول إليها بواسطة علامتها لاحقًا:
void NSNibWakingOverride::awakeFromNib (NSControl * this ) {
OMasterDictionaryPtr-> addObject :withTag:( this , this -> _tag ));
}لكن هذا يعتمد على قراءة NSControl._tag ، وهو مجال خاص. في MacOS 10.9 التي نجحت لأن NSControl تم تعريفها على هذا النحو:
@interface NSControl : NSView
{
/* All instance variables are private */
NSInteger _tag;
id _cell;
struct __conFlags {
...
} _conFlags;
}ولكن في MacOS 10.10 ، تم إعادة تمثيل NSControl لتحريك حقل _TAG إلى حقل جديد _aux ، مما يجعله غير ممكن:
@interface NSControl : NSView
{
/* All instance variables are private */
NSControlAuxiliary *_aux;
id _cell;
struct __conFlags {
...
} _conFlags;
}
@property NSInteger tag;لقد قمت بتصحيح Awakefromnib لجعلها تتصل بشكل صحيح بوظيفة الملحقات العامة لهذا الحقل:
void NSNibWakingOverride::awakeFromNib (NSControl * this ) {
OMasterDictionaryPtr-> addObject :withTag:( this , this -> tag ()));
}في وظيفة Wacom's OpOpuPoutlineView :: Reloaddata () ، يتم قراءة حقل NstableView._datasource الخاص مباشرة:
void OPopupOutlineView::reloadData (OPopupOutlineView * this ) {
this -> _dataSource . willReloadDataForOutlineView ( this );
...
}لذلك قمت بتصحيح هذا لاستخدام الملحق العام بدلاً من ذلك:
void OPopupOutlineView::reloadData (OPopupOutlineView * this ) {
this -> dataSource ()-> willReloadDataForOutlineView ( this );
...
} هذه السائقين لديها نفس المشكلات التي يشكلها برامج تشغيل Graphire 3 و 4 ، بالإضافة إلى نفس مشكلة _dataSource في ORadialSubMenuTableView::reloadData() method ، مع نفس الإصلاح.