From: 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 处设置断点之后,程序就能在该代码处中断了,我们从而知道代码在什么地方出问题了。
package com.cjy.map;
import com.autonavi.mapapi.GeoPoint;
import com.autonavi.mapapi.LocationManagerProxy;
import com.autonavi.mapapi.LocationProviderProxy;
import com.autonavi.mapapi.MapActivity;
import com.autonavi.mapapi.MapController;
import com.autonavi.mapapi.MapView;
import com.autonavi.mapapi.MyLocationOverlay;
import android.content.Context;
//
//import android.location.Location;
//import android.location.LocationListener;
//import android.location.LocationManager;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
public class MapGdActivity extends MapActivity {
/** Called when the activity is first created. */
MapView map = null;
MapController ctrlMap = null;
MyLocationOverlay mylocTest;
GeoPoint point;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
map = (MapView) findViewById(R.id.mylocationview);
map.setBuiltInZoomControls(true); //
ctrlMap = map.getController();
// 得到mMapView的控制权,可以用它控制和驱动平移和缩放
point = new GeoPoint((int) (34.299999 * 1E6),// 西安的经纬度
(int) (108.930000 * 1E6)); // 用给定的经纬度构造一个GeoPoint,单位是微度 (度 * //
// 1E6)
ctrlMap.setCenter(point); // 设置地图中心点
ctrlMap.setZoom(12); // 设置地图zoom级别
//map.setTraffic(true);//设置地图为交通模式
//map.setStreetView(true);
//设置为卫星模式
map.setSatellite(true);
ctrlMap = map.getController();
mylocTest = new MyLocationOverlay(MapGdActivity.this, map);
mylocTest.enableMyLocation();
mylocTest.enableCompass(); // 打开指南针
map.getOverlays().add(mylocTest);
LocationManagerProxy managerProxy = new LocationManagerProxy(this);
managerProxy.requestLocationUpdates(LocationProviderProxy.AutonaviCellProvider,
2000, 0, locationListener);
}
private void getLocationInfo(Location location) {
String latLongInfo;
TextView locationText = (TextView) findViewById(R.id.tv);
if (location != null) {
double lat = location.getLatitude();
double lng = location.getLongitude();
latLongInfo = "Lat: " + lat + "\nLong: " + lng;
} else {
latLongInfo = "No location found";
}
locationText.setText("Your Current Position is:\n" + latLongInfo);
}
private final LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
Log.e(MapGdActivity.class.getName(), "onLocationChanged");
getLocationInfo(location);
Toast.makeText(
MapGdActivity.this,
location.getAltitude() + "---" + location.getLatitude()
+ "---" + location.getLongitude(),
Toast.LENGTH_LONG).show();
}
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
Log.e(MapGdActivity.class.getName(), "onProviderDisabled=="
+ provider);
}
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
Log.e(MapGdActivity.class.getName(), "onProviderEnabled=="
+ provider);
}
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
Log.e(MapGdActivity.class.getName(), "onStatusChanged==" + provider);
}
};
}
class LocactionM extends LocationManagerProxy {
public LocactionM(Context arg0, String arg1) {
super(arg0, arg1);
// TODO Auto-generated constructor stub
}
}
viewgroup简单说就是可以装view的view.今天遇到一个问题,就是需要一个可以自动根据一行中view的宽度自动换行的布局,网上找了下,没有相关的例子,但是找到了思路:自定义一个viewgroup,然后在onlayout文件里面自动检测view的右边缘的横坐标值,和你的view的parent view的况度判断是否换行显示view就可以了。因为代码比较简单,就不多说了:
1 public class MyViewGroup extends ViewGroup { 2 private final static String TAG = "MyViewGroup"; 3 4 private final static int VIEW_MARGIN=2; 5 6 public MyViewGroup(Context context) { 7 super(context); 8 } 9 @Override 10 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 11 Log.d(TAG, "widthMeasureSpec = "+widthMeasureSpec+" heightMeasureSpec"+heightMeasureSpec); 12 13 for (int index = 0; index < getChildCount(); index++) { 14 final View child = getChildAt(index); 15 // measure 16 child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 17 } 18 19 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 20 } 21 22 @Override 23 protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) { 24 Log.d(TAG, "changed = "+arg0+" left = "+arg1+" top = "+arg2+" right = "+arg3+" botom = "+arg4); 25 final int count = getChildCount(); 26 int row=0;// which row lay you view relative to parent 27 int lengthX=arg1; // right position of child relative to parent 28 int lengthY=arg2; // bottom position of child relative to parent 29 for(int i=0;i<count;i++){ 30 31 final View child = this.getChildAt(i); 32 int width = child.getMeasuredWidth(); 33 int height = child.getMeasuredHeight(); 34 lengthX+=width+VIEW_MARGIN; 35 lengthY=row*(height+VIEW_MARGIN)+VIEW_MARGIN+height+arg2; 36 //if it can't drawing on a same line , skip to next line 37 if(lengthX>arg3){ 38 lengthX=width+VIEW_MARGIN+arg1; 39 row++; 40 lengthY=row*(height+VIEW_MARGIN)+VIEW_MARGIN+height+arg2; 41 42 } 43 44 child.layout(lengthX-width, lengthY-height, lengthX, lengthY); 45 } 46 47 } 48 49 }
这里有个地方要注意,那就要明白ViewGroup的绘图流程:ViewGroup绘制包括两个步骤:1.measure 2.layout
在两个步骤中分别调用回调函数:1.onMeasure() 2.onLayout()
1.onMeasure() 在这个函数中,ViewGroup会接受childView的请求的大小,然后通过childView的 measure(newWidthMeasureSpec, heightMeasureSpec)函数存储到childView中,以便childView的getMeasuredWidth() andgetMeasuredHeight() 的值可以被后续工作得到。
2.onLayout() 在这个函数中,ViewGroup会拿到childView的getMeasuredWidth() andgetMeasuredHeight(),用来布局所有的childView。
3.View.MeasureSpec 与 LayoutParams 这两个类,是ViewGroup与childView协商大小用的。其中,View.MeasureSpec是ViewGroup用来部署 childView用的, LayoutParams是childView告诉ViewGroup 我需要多大的地方。
4.在View 的onMeasure的最后要调用setMeasuredDimension()这个方法存储View的大小,这个方法决定了当前View的大小。
效果图: