📲

【print】objc_util からrubicon-objc へ移行【デバッグ】

2024/03/30に公開

objc_util で独自に作って活用していたもの

objc_util のprint デバッグ。Pythonista3 の黒魔術 #Python - Qiita

objc_utilオブジェクトの持っているメソッドを確認する時に活用していたが、objc_util依存なので、rubiconに書き換えた。
rubiconでは、objc_utilそっくりにはいかないので、(写経しつつ)機能を追加してみた。

実装全容

pdbr.py
import ctypes
import json
from pprint import pprint

from rubicon.objc import ObjCInstance, ObjCClass, NSObject
from rubicon.objc.runtime import libobjc

__all__ = [
  'state',
]


def _get_className_methods(rubicon_object):
  if rubicon_object == None:
    return None
  objct_class = libobjc.object_getClass(rubicon_object)
  py_className_methods = {}
  is_flag = False

  while objct_class is not None:
    py_methods = []
    num_methods = ctypes.c_uint(0)
    method_list_ptr = libobjc.class_copyMethodList(objct_class,
                                                   ctypes.byref(num_methods))
    for i in range(num_methods.value):
      selector = libobjc.method_getName(method_list_ptr[i])
      sel_name = libobjc.sel_getName(selector).decode('ascii')
      py_method_name = sel_name.replace(':', '_')

      if '.' not in py_method_name:
        py_methods.append(py_method_name)
    libobjc.free(method_list_ptr)

    py_className_methods[str(ObjCInstance(objct_class.value))] = sorted(
      set(py_methods))

    objct_class = libobjc.class_getSuperclass(objct_class)

    if is_flag:
      break
    if objct_class.value == NSObject.ptr.value:
      is_flag = True

  return dict(reversed(list(py_className_methods.items())))


def state(rubicon_obj):
  _dic = _get_className_methods(rubicon_obj)
  if _dic:
    data = json.dumps(_dic, indent=2)
    print(data)
    pprint(list(_dic.keys()))
    pprint(rubicon_obj)
  else:
    print(rubicon_obj)

ざっくり解説

PythonistaAppTemplate/PythonistaAppTemplate/PythonistaKit.framework/pylib/site-packages/objc_util.py at f560f93f8876d82a21d108977f90583df08d55af · omz/PythonistaAppTemplate

ObjCInstance classの__dir__ を写経。
本家(objc_util)だとsuper classのmethodも、list で一括にまとめられていたが、今回はclassごとに取得をして、dict 形式としてkey valueで持たせている。

updateメモ

  • 生やしていた引数を削除
    • デフォルトで、NSObject を先頭に
  • NSObject のmethod取得が事前決め打ちだったものを、実際に読み込んで格納
  • classごとのmethodに分けたが、全体としてどのようなclassを持っているか把握し辛かったので、class名を配列で吐くようにした
  • None の場合、無限ループになるので、if で逃している(よく無い)

Discussion