看了牛人的这篇文章,感觉真是很有用啊,受益匪浅 http://blog.csdn.net/kesalin/article/details/7222153
XCode 内置GDB,我们可以在命令行中使用 GDB 命令来调试我们的程序。下面将介绍一些常用的命令以及调试技巧。
po 命令:为 print object 的缩写,显示对象的文本描述(显示从对象的 description 消息获得的字符串信息)。
比如:
上图中,我使用 po 命令显示一个 NSDictionary 的内容。注意在左侧我们可以看到 dict 的一些信息:3 key/value pairs,显示该 dict 包含的数据量,而展开的信息显示 isa 层次体系(即class
和 metaclass结构关系)。我们可以右击左侧的 dict,选中“Print Description of "dict"”,则可以在控制台输出 dict 的详细信息:
print 命令:有点类似于格式化输出,可以输出对象的不同信息:
如:
注:4是 NSUTF8StringEncoding 的值。
info 命令:我们可以查看内存地址所在信息
比如 "info symbol 内存地址" 可以获取内存地址所在的 symbol 相关信息:
比如 "info line *内存地址" 可以获取内存地址所在的代码行相关信息:
show 命令:显示 GDB 相关的信息。如:show version 显示GDB版本信息
help 命令:如果忘记某条命令的语法了,可以使用 help 命令名 来获取帮助信息。如:help info 显示 info 命令的用法。
在系统抛出异常处设置断点
有时候我们的程序不知道跑到哪个地方就 crash 了,而 crash 又很难重现。保守的做法是在系统抛出异常之前设置断点,具体来说是在 objc_exception_throw处设置断点。设置步骤为:首先在 XCode 按 CMD + 6,进入断点管理窗口;然后点击右下方的 +,增加新的 Symbolic Breakpoint,在 Symbol 一栏输入:objc_exception_throw,然后点击
done,完成。 这样在 Debug 模式下,如果程序即将抛出异常,就能在抛出异常处中断了。比如在前面的代码中,我让 [firstObjctcrashTest]; 抛出异常。在 objc_exception_throw 处设置断点之后,程序就能在该代码处中断了,我们从而知道代码在什么地方出问题了。
public class RootPathFunction extends CordovaPlugin {
private static final String TAG = RootPathFunction.class.getSimpleName();
private String mActionName = "rootFilePath";
private Context context;
private String filePath = "/www/";
private String path;
@Override
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
super.initialize(cordova, webView);
context = cordova.getActivity();
Log.e(TAG, "initialize");
File root = Environment.getExternalStorageDirectory();// getDataDirectory();
File rootRes = new File(root.getPath() + filePath);
path = rootRes.getPath();
//copyAssets("www", path);
copyAssets2("www");
}
@Override
public boolean execute(String action, JSONArray args,
CallbackContext callbackContext) throws JSONException {
Log.e(TAG, "execute action="/blog_article/action/index.html",args=" + args.toString());
if (action.equals(mActionName)) {
callbackContext.success(path);
return true;
} else {
callbackContext.error("rootFilePath is failed!");
return false;
}
}
private void copyAssets(String assetDir, String dir) {
String[] files;
try {
files = context.getResources().getAssets().list(assetDir);
} catch (IOException e1) {
return;
}
File mWorkingPath = new File(dir);
if (!mWorkingPath.exists()) {
mWorkingPath.mkdirs();
}
for (int i = 0; i < files.length; i++) {
try {
String fileName = files[i];
if (isFolder(fileName)) {
if (0 == assetDir.length()) {
copyAssets(fileName, dir + File.separator + fileName
+ File.separator);
} else {
copyAssets(assetDir + File.separator + fileName, dir
+ File.separator + fileName + File.separator);
}
continue;
}
File outFile = new File(mWorkingPath, fileName);
if (outFile.exists())
outFile.delete();
InputStream in = null;
if (0 != assetDir.length())
in = context.getAssets().open(
assetDir + File.separator + fileName);
else
in = context.getAssets().open(fileName);
OutputStream out = new FileOutputStream(outFile);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
String[] suffixs = { ".png", ".jpg", ".css", ".js", ".html", ".htm",
".jsp", ".apx", ".txt", ".LICENSE" };
private boolean isFolder(String fileName) {
for (int i = 0; i < suffixs.length; i++) {
if (fileName.contains(suffixs[i])) {
return false;
}
}
return true;
}
private void copyAssets2(String assetDir) {
String[] files;
try {
files = context.getResources().getAssets().list(assetDir);
} catch (IOException e1) {
return;
}
for (int i = 0; i < files.length; i++) {
try {
String fileName = files[i];
if (isFolder(fileName)) {
continue;
}
FileOutputStream fileOutputStream = context.openFileOutput(fileName, context.MODE_WORLD_WRITEABLE);
InputStream in = null;
if (0 != assetDir.length())
in = context.getAssets().open(
assetDir + File.separator + fileName);
else
in = context.getAssets().open(fileName);
OutputStream out = fileOutputStream;
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package com.example.googleandroiddemo; // //import android.app.Activity; //import android.os.Bundle; //import android.support.v4.app.FragmentTransaction; //import android.support.v4.app.ListFragment; //import android.view.View; //import android.widget.ArrayAdapter; //import android.widget.ListView; // //public class MainActivity extends Activity { // @Override // protected void onCreate(Bundle savedInstanceState) { // super.onCreate(savedInstanceState); // // setContentView(R.layout.fragment_layout); // } // // // public static class TitlesFragment extends ListFragment { // public TitlesFragment() { // super(); // // TODO Auto-generated constructor stub // } // // public static TitlesFragment newInstance(int index) { // TitlesFragment f = new TitlesFragment(); // // // Supply index input as an argument. //// Bundle args = new Bundle(); //// args.putInt("index", index); //// f.setArguments(args); // // return f; // } // // boolean mDualPane; // int mCurCheckPosition = 0; // String str[] = { "321321", "312312", "312312", "321321312","eqweqwewqeqw","eqwewqeqwwe","eqweqweqwerewre","r4r4r4t","eqwewqe" }; // @Override // public void onActivityCreated(Bundle savedInstanceState) { // super.onActivityCreated(savedInstanceState); // // // Populate list with our static array of titles. // setListAdapter(new ArrayAdapter<String>(getActivity(), // android.R.layout.simple_list_item_activated_1, // str)); // // // Check to see if we have a frame in which to embed the details // // fragment directly in the containing UI. // View detailsFrame = getActivity().findViewById(R.id.details); // mDualPane = detailsFrame != null // && detailsFrame.getVisibility() == View.VISIBLE; // // if (savedInstanceState != null) { // // Restore last state for checked position. // mCurCheckPosition = savedInstanceState.getInt("curChoice", 0); // } // // if (mDualPane) { // // In dual-pane mode, the list view highlights the selected item. // getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); // // Make sure our UI is in the correct state. // showDetails(mCurCheckPosition); // } // } // // @Override // public void onSaveInstanceState(Bundle outState) { // super.onSaveInstanceState(outState); // outState.putInt("curChoice", mCurCheckPosition); // } // // @Override // public void onListItemClick(ListView l, View v, int position, long id) { // showDetails(position); // } // // /** // * Helper function to show the details of a selected item, either by // * displaying a fragment in-place in the current UI, or starting a whole new // * activity in which it is displayed. // */ // void showDetails(int index) { // mCurCheckPosition = index; // // if (mDualPane) { // // We can display everything in-place with fragments, so update // // the list to highlight the selected item and show the data. // getListView().setItemChecked(index, true); // // // Check what fragment is currently shown, replace if needed. // DetailsFragment details = (DetailsFragment) getFragmentManager() // .findFragmentById(R.id.details); // if (details == null || details.getShownIndex() != index) { // // Make new fragment to show this selection. // details = DetailsFragment.newInstance(index); // // // Execute a transaction, replacing any existing fragment // // with this one inside the frame. // FragmentTransaction ft = getFragmentManager() // .beginTransaction(); // ft.replace(R.id.details, details); // ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); // ft.commit(); // } // // } else { // // Otherwise we need to launch a new activity to display // // the dialog fragment with selected text. // // Intent intent = new Intent(); // // intent.setClass(getActivity(), DetailsActivity.class); // // intent.putExtra("index", index); // // startActivity(intent); // } // } // } //} import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; import android.app.AlertDialog; import android.app.Fragment; import android.app.FragmentTransaction; import android.app.ListFragment; import android.os.Bundle; //import android.support.v4.app.Fragment; //import android.support.v4.app.FragmentTransaction; //import android.support.v4.app.ListFragment; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.ScrollView; import android.widget.TextView; public class MainActivity extends Activity { public static String[] array = { "text1,", "text2", "text3", "text4", "text5,", "text6", "text7", "text8" }; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_layout); } public static class TitlesFragment extends ListFragment { boolean mDualPane; int mCurCheckPosition = 0; @Override public void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); System.out.println("Fragment-->onCreate"); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO Auto-generated method stub System.out.println("Fragment-->onCreateView"); return super.onCreateView(inflater, container, savedInstanceState); } @Override public void onPause() { // TODO Auto-generated method stub super.onPause(); System.out.println("Fragment-->onPause"); } @Override public void onStop() { // TODO Auto-generated method stub super.onStop(); System.out.println("Fragment-->onStop"); } @Override public void onAttach(Activity activity) { // TODO Auto-generated method stub super.onAttach(activity); System.out.println("Fragment-->onAttach"); } @Override public void onStart() { // TODO Auto-generated method stub super.onStart(); System.out.println("Fragment-->onStart"); } @Override public void onResume() { // TODO Auto-generated method stub super.onResume(); System.out.println("Fragment-->onResume"); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); System.out.println("Fragment-->onDestroy"); } @Override public void onActivityCreated(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onActivityCreated(savedInstanceState); System.out.println("Fragment-->onActivityCreted"); setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, array)); View detailsFrame = getActivity().findViewById(R.id.details); mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE; if (savedInstanceState != null) { mCurCheckPosition = savedInstanceState.getInt("curChoice", 0); //从保存的状态中取出数据 } if (mDualPane) { getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); showDetails(mCurCheckPosition); } } @Override public void onSaveInstanceState(Bundle outState) { // TODO Auto-generated method stub super.onSaveInstanceState(outState); outState.putInt("curChoice", mCurCheckPosition);//保存当前的下标 } @Override public void onListItemClick(ListView l, View v, int position, long id) { // TODO Auto-generated method stub super.onListItemClick(l, v, position, id); showDetails(position); } void showDetails(int index) { mCurCheckPosition = index; if (mDualPane) { getListView().setItemChecked(index, true); DetailsFragment details = (DetailsFragment) getFragmentManager() .findFragmentById(R.id.details); if (details == null || details.getShownIndex() != index) { details = DetailsFragment.newInstance(mCurCheckPosition); //得到一个fragment 事务(类似sqlite的操作) FragmentTransaction ft = getFragmentManager() .beginTransaction(); ft.replace(R.id.details, details);//将得到的fragment 替换当前的viewGroup内容,add则不替换会依次累加 ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);//设置动画效果 ft.commit();//提交 } } else { new AlertDialog.Builder(getActivity()).setTitle( android.R.string.dialog_alert_title).setMessage( array[index]).setPositiveButton(android.R.string.ok, null).show(); } } } /** * 作为界面的一部分,为fragment 提供一个layout * @author terry * */ public static class DetailsFragment extends Fragment { public static DetailsFragment newInstance(int index) { DetailsFragment details = new DetailsFragment(); Bundle args = new Bundle(); args.putInt("index", index); details.setArguments(args); return details; } public int getShownIndex() { return getArguments().getInt("index", 0); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO Auto-generated method stub if (container == null) return null; ScrollView scroller = new ScrollView(getActivity()); TextView text = new TextView(getActivity()); int padding = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 4, getActivity() .getResources().getDisplayMetrics()); text.setPadding(padding, padding, padding, padding); scroller.addView(text); text.setText(array[getShownIndex()]); return scroller; } } }
xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <fragment android:id="@+id/titles" android:layout_weight="1" android:layout_width="0px" android:layout_height="match_parent" /> <FrameLayout android:id="@+id/details" android:layout_weight="1" android:layout_width="0px" android:layout_height="match_parent" android:background="?android:attr/detailsElementBackground" ></FrameLayout> </LinearLayout>