在自定义的视图控制器类中,通过代码添加uitableview对象和mkmapview对象,实现两个视图对象的展现切换。tableview的delegate和datasource也在这个自定义的视图控制器类中实现。这样就不用依赖于XCODE提供的uitableviewcontroller类。这样更加灵活,有利于开发出更强大的应用。
根据展现顺序,使用多线程加载后一个mkmapview对象,企图实现更友好的展现效果。我设想的,开始只需要显示一个tableview,而mapview是在后台不用立即显示出来。另外,如果加载到tableview的数据是来自网络,而不是测试中本地,那么也可以用多线程来实现。
我列举了两种多线程的使用方法,一种是NSOperationQueue,另一种是dispatch_async。两种方法孰优孰劣,我也不知道。对此有研究的网友请指点一二。
下面给出源码,如下所示:
#import <UIKit/UIKit.h>
@interface XYViewController : <UITableViewDelegate,UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UIBarButtonItem *switchMapAndList;
- (IBAction)switchListOrMap:(id)sender;
@end
#import "XYViewController.h"
#import "XYTableView.h"
#import <MapKit/MapKit.h>
@interface XYViewController ()
{
XYTableView *resultList;
NSMutableArray *dataArray1;
NSMutableArray *dataArray2;
NSMutableArray *titleArray;
UIImageView *resultImg;
MKMapView *resultMap;
int listOrMap;
}
@end
@implementation XYViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
resultList=[[XYTableView alloc] init];
[resultList setDelegate:self];
[resultList setDataSource:self];
[self.view addSubview:resultList];
dataArray1 = [[NSMutableArray alloc] initWithObjects:@"中国", @"美国", @"英国", nil];
dataArray2 = [[NSMutableArray alloc] initWithObjects:@"黄种人", @"黑种人", @"白种人", nil];
titleArray = [[NSMutableArray alloc] initWithObjects:@"国家", @"种族", nil];
listOrMap=0;
resultMap=[[MKMapView alloc] initWithFrame:CGRectMake(0, 50, 320, 410)];
/*
dispatch_queue_t qq=dispatch_queue_create("addsubview_queue",nil);
dispatch_async(qq,^(void){
[resultMap setAlpha:0.0];
[self.view addSubview:resultMap];
});
dispatch_release(qq);
*/
NSOperationQueue *queue=[[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^(void){
[resultMap setAlpha:0.0];
[self.view addSubview:resultMap];
}];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
switch (section) {
case 0:
return [titleArray objectAtIndex:section];//提取标题数组的元素用来显示标题
case 1:
return [titleArray objectAtIndex:section];//提取标题数组的元素用来显示标题
default:
return @"Unknown";
}
}
//指定有多少个分区(Section),默认为1
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [titleArray count];//返回标题数组中元素的个数来确定分区的个数
}
//指定每个分区中有多少行,默认为1
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
switch (section) {
case 0:
return [dataArray1 count];//每个分区通常对应不同的数组,返回其元素个数来确定分区的行数
break;
case 1:
return [dataArray2 count];
break;
default:
return 0;
break;
}
}
//绘制Cell
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
//初始化cell并指定其类型,也可自定义cell
UITableViewCell *cell = (UITableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell=[[UITableViewCell alloc] initWithFrame:CGRectZero];
//cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier];
}
switch (indexPath.section) {
case 0://对应各自的分区
[[cell textLabel] setText:[dataArray1 objectAtIndex:indexPath.row]];//给cell添加数据
break;
case 1:
[[cell textLabel] setText:[dataArray2 objectAtIndex:indexPath.row]];
break;
default:
[[cell textLabel] setText:@"Unknown"];
}
return cell;//返回cell
}
- (IBAction)switchListOrMap:(id)sender {
self.switchMapAndList.title=listOrMap==0?@"list":@"map";
listOrMap=listOrMap==0?1:0;
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewContentModeBottom
animations:^{
[resultMap setAlpha:listOrMap];
}
completion:^(BOOL completed){
}];
}
@end
阅读完这段代码,眼睛累。那么,就养养眼吧。
目前基于高通的code分析:
1. 引入libOmxCore.so根据stagefright 架构分析(七) 动态加载libstagefrighthw.so中的描述
Plugin会加载libOmxCore.so,并调用相应的functions
OMX_Init
OMX_Deinit
OMX_ComponentNameEnum
OMX_GetHandle
OMX_FreeHandle
OMX_GetRolesOfComponent
2. libOmxCore.so 编译内容LOCAL_SRC_FILES := src/common/omx_core_cmp.cpp
LOCAL_SRC_FILES += src/common/qc_omx_core.c
LOCAL_SRC_FILES += src/$(MM_CORE_TARGET)/qc_registry_table_android.c
QComOMXPlugin中通过dlsym得到的函数指针,是在qc_omx_core.c中实现的。
例如 mInit = (InitFunc)dlsym(mLibHandle, "OMX_Init");
(*mInit)();
最终调用的是
OMX_API OMX_ERRORTYPE OMX_APIENTRY
OMX_Init()
{
DEBUG_PRINT("OMXCORE API - OMX_Init \n");
/* Nothing to do here ; shared objects shall be loaded at the get handle method */
return OMX_ErrorNone;
}
component interface在omx_core_cmp.cpp中实现:
具体看这个函数,就容易理解了
void * qc_omx_create_component_wrapper(OMX_PTR obj_ptr)
{
qc_omx_component *pThis = (qc_omx_component *)obj_ptr;
OMX_COMPONENTTYPE* component = &(pThis->m_cmp);
memset(&pThis->m_cmp,0,sizeof(OMX_COMPONENTTYPE));
component->nSize = sizeof(OMX_COMPONENTTYPE);
component->nVersion.nVersion = OMX_SPEC_VERSION;
component->pApplicationPrivate = 0;
component->pComponentPrivate = obj_ptr;
component->AllocateBuffer = &qc_omx_component_allocate_buffer;
component->FreeBuffer = &qc_omx_component_free_buffer;
component->GetParameter = &qc_omx_component_get_parameter;
component->SetParameter = &qc_omx_component_set_parameter;
component->SendCommand = &qc_omx_component_send_command;
component->FillThisBuffer = &qc_omx_component_fill_this_buffer;
component->EmptyThisBuffer = &qc_omx_component_empty_this_buffer;
component->GetState = &qc_omx_component_get_state;
component->GetComponentVersion = &qc_omx_component_get_version;
component->GetConfig = &qc_omx_component_get_config;
component->SetConfig = &qc_omx_component_set_config;
component->GetExtensionIndex = &qc_omx_component_get_extension_index;
component->ComponentTunnelRequest = &qc_omx_component_tunnel_request;
component->UseBuffer = &qc_omx_component_use_buffer;
component->SetCallbacks = &qc_omx_component_set_callbacks;
component->UseEGLImage = &qc_omx_component_use_EGL_image;
component->ComponentRoleEnum = &qc_omx_component_role_enum;
component->ComponentDeInit = &qc_omx_component_deinit;
return (void *)component;
}
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component) {
//调用GetHandle,注册callbacks,并用name得到component句柄
return (*mGetHandle)(
reinterpret_cast<OMX_HANDLETYPE *>(component),
const_cast<char *>(name),
appData, const_cast<OMX_CALLBACKTYPE *>(callbacks));
}
OMX_API OMX_ERRORTYPE OMX_APIENTRY
OMX_GetHandle(OMX_OUT OMX_HANDLETYPE* handle,
OMX_IN OMX_STRING componentName,
OMX_IN OMX_PTR appData,
OMX_IN OMX_CALLBACKTYPE* callBacks)
{
//根据componentName获得对应的component的index
cmp_index = get_cmp_index(componentName);
// dynamically load the so
core[cmp_index].fn_ptr =
omx_core_load_cmp_library(core[cmp_index].so_lib_name,
&core[cmp_index].so_lib_handle);
//创建instance指针地址
void* pThis = (*(core[cmp_index].fn_ptr))();
if(pThis)
{
void *hComp = NULL;
//这就是前面注册component
hComp = qc_omx_create_component_wrapper((OMX_PTR)pThis);
//初始化component
if((eRet = qc_omx_component_init(hComp, core[cmp_index].name)) !=
OMX_ErrorNone)
qc_omx_component_set_callbacks(hComp,callBacks,appData);
//得到component handle的index
hnd_index = get_comp_handle_index(componentName);
if(hnd_index >= 0)
{
//最终将创建好的component handle返回
core[cmp_index].inst[hnd_index]= *handle = (OMX_HANDLETYPE) hComp;
}
}
6. 如何根据ComponentName找到对应的handle呢? static int get_cmp_index(char *cmp_name){
for(i=0; i< (int)SIZE_OF_CORE; i++)
{
if(!strcmp(cmp_name, core[i].name))
{
rc = i;
break;
}
}
return rc;
}
可以看到,是根据全局数组core中找到的
core的定义在$(MM_CORE_TARGET)/qc_registry_table_android.c
不同的TARGET有不同的定义
omx_core_cb_type core[] =
{
{
"OMX.qcom.video.decoder.avc",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxVdec.so",
{
"video_decoder.avc"
}
},
{
"OMX.qcom.video.decoder.avc.secure",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxVdec.so",
{
"video_decoder.avc"
}
},
{
"OMX.qcom.video.decoder.divx4",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxVdec.so",
{
"video_decoder.divx"
}
},
{
"OMX.qcom.video.decoder.divx",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxVdec.so",
{
"video_decoder.divx"
}
},
{
"OMX.qcom.video.decoder.divx311",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxVdec.so",
{
"video_decoder.divx"
}
},
{
"OMX.qcom.video.decoder.mpeg4",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxVdec.so",
{
"video_decoder.mpeg4"
}
},
{
"OMX.qcom.video.decoder.mpeg2",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxVdec.so",
{
"video_decoder.mpeg2"
}
},
{
"OMX.qcom.video.decoder.vc1",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxVdec.so",
{
"video_decoder.vc1"
}
},
{
"OMX.qcom.video.decoder.wmv",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxVdec.so",
{
"video_decoder.vc1"
}
},
{
"OMX.qcom.video.decoder.h263",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxVdec.so",
{
"video_decoder.h263"
}
},
{
"OMX.qcom.video.encoder.mpeg4",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxVenc.so",
{
"video_encoder.mpeg4"
}
},
{
"OMX.qcom.video.encoder.h263",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxVenc.so",
{
"video_encoder.h263"
}
},
{
"OMX.qcom.video.encoder.avc",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxVenc.so",
{
"video_encoder.avc"
}
},
{
"OMX.qcom.audio.decoder.Qcelp13",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxQcelp13Dec.so",
{
"audio_decoder.Qcelp13"
}
},
{
"OMX.qcom.audio.decoder.evrc",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxEvrcDec.so",
{
"audio_decoder.evrc"
}
},
{
"OMX.qcom.audio.decoder.wma",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxWmaDec.so",
{
"audio_decoder.wma"
}
},
{
"OMX.qcom.audio.decoder.wma10Pro",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxWmaDec.so",
{
"audio_decoder.wma"
}
},
{
"OMX.qcom.audio.decoder.aac",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxAacDec.so",
{
"audio_decoder.aac"
}
},
{
"OMX.qcom.audio.encoder.aac",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxAacEnc.so",
{
"audio_encoder.aac"
}
},
{
"OMX.qcom.audio.encoder.qcelp13",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxQcelp13Enc.so",
{
"audio_encoder.qcelp13"
}
},
{
"OMX.qcom.audio.encoder.evrc",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxEvrcEnc.so",
{
"audio_encoder.evrc"
}
},
{
"OMX.qcom.audio.encoder.amrnb",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxAmrEnc.so",
{
"audio_encoder.amrnb"
}
},
{
"OMX.qcom.audio.decoder.aac",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxAacDec.so",
{
"audio_decoder.aac"
}
},
{
"OMX.qcom.audio.decoder.multiaac",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxAacDec.so",
{
"audio_decoder.aac"
}
},
{
"AIV.play",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libAivPlay.so",
{
"AIV.play.101"
}
},
{
"OMX.qcom.file.muxer",
NULL, // Create instance function
// Unique instance handle
{
NULL,
NULL,
NULL,
NULL
},
NULL, // Shared object library handle
"libOmxMux.so",
{
"container_muxer.mp2"
}
}
};
const unsigned int SIZE_OF_CORE = sizeof(core) / sizeof(omx_core_cb_type);
编者按:
早在上个世纪八九十年代就曾经有人预言,属于ARM的新帝国与Intel领导的PC帝国之间,迟早必有一战,而这个预言也在今日得到应验。
ARM与Intel的恩怨纠葛由来已久,自上个世纪80年代ARM公司成立以来,向前迈出的每一步,都伴随着Intel的身影。与Intel这样强大的对手处于同一时代,既是不幸,也是万幸。在移动互联网的大潮到来之前,ARM始终生活在Intel的阴影之下,在夹缝中寻求生存机会,同时,也由于Intel有意无意的推动与威胁,强迫ARM不断的向前发展,最终成就了ARM一方霸主的地位。
ARM公司于1978年成立于剑桥大学,最初研发了基于MOS Technology 6502处理器的BBC Micro处理器系统,这颗处理器在上世纪80年代至90年代,曾主宰了英国的教育市场,但这并没有给ARM带来可观的收益,更可怕的是,此时ARM迎来了一生的对手——Intel,在强大的Intel面前,弱小的ARM别无选择,只能妥协。ARM希望与Intel合作,并向Intel申请286处理器样片,但不幸的是,遭到了Intel无情地拒绝。
没有退路的ARM不得不考虑研制一颗属于自己的处理器。由于采用X86架构的Intel处理器过于强势,ARM无法正面回击。而X86采用的是CISC(复杂指令集),强调高性能,因此,为了避开与Intel的竞争,ARM重新定义了自己的设计理念:低成本、低功耗、高效率,也因此选择了RISC(精简指令集)。
严格来讲,这样的设计理念与当时的市场潮流并不吻合,但ARM别无选择。而凑巧的是,若干年后的今天,这个理念与智能手机的需求不谋而合。也因此成就了ARM的神话。
1983年10月,ARM开启研发计划,直到1985年4月26日,第一个ARM处理器架构——ARM1问世。但是由于ARM1的结构过于简单,当时并没有引起人们的注意,而同年10月17日Intel发布的386处理器几乎吸引了所有人的目光。这也注定了ARM1的无所作为。
由于财务状况遭遇危机,1985年2月,不得不将49.3%的股份出售给当时的IT巨头Olivetti, 但是Olivetti的庇护没有给ARM带来机遇。Olivetti企图涉足PC领域,挑战在这个领域的霸主Intel。对ARM并不重视,仅仅将ARM处理器用于研发。ARM的状况变得更加糟糕,看不到希望的ARM最终决定独立。
1990年11月,ARM与Apple和VLSI共同出资创建了新的ARM,并把公司名称由“Acorn RISC Machine”更名为“Advanced RISC Machine”。Apple投入3百万美金拥有了ARM公司43%的股份,主要用于苹果当时正在研发的Newton项目,这个项目的终极目标就是生产世界上第一台平板电脑,显而易见,由于理念过于超前,这个项目最终夭折。(十几年后,乔布斯再次推出iPad,席卷了全球。)
1998年,ARM公司在英国和美国同时上市,但是由于Newton项目被乔布斯取消,ARM失去了利用价值,Apple逐渐卖出了所持ARM的股份。然而今天,Apple即使准备付出100倍的代价,也无法购回这些股份。
在此期间,ARM还迎来了另一个转机,1993年,Cirrus Logic和德州仪器公司TI(Texas Instruments)先后加入ARM阵营。并开始与诺基亚进行合作。此后,诺基亚的巨大成功,使得ARM逐渐摆脱了财务危机,业务不断扩大。至1993年底,ARM已有50个员工,销售额达到10M英镑。
同年,ARM迎来了公司成立以来最重要的一颗处理器内核——ARM7,这颗内核引起了当时的处理器巨头DEC的关注,DEC获得了ARM架构的完整授权,并于1995年开始研发基于ARM指令集的StrongARM内核,并且得到了业界的广泛认可。StrongARM的成功也使得ARM开始被业界关注。
不过由于DEC技术与商业的严重背离,在与Intel的竞争中很快败下阵来,直到1998年,DEC逐渐变卖了自己的全部资产,而Intel从DEC手中获得了StrongARM与ARM架构的完整授权,这也使得Intel与ARM第一次走到了一起。
StrongARM的注入使Intel的处理器迈入新的时代,Intel具备了向所有RISC处理器同时宣战的能力,最终一统PC和服务器领域。被Intel收购后,StrongARM拥有了一个新名字——XScale,加上Intel强大的生态系统,XScale强势进军嵌入式领域。
从1998年到2006年期间,XScale处理器席卷了整个嵌入式领域。甚至将当时的王者摩托罗拉半导体打的一蹶不振。Intel的处理器技术极大地促进了ARM内核的发展,对ARM今后的成功起到了重大的推动作用。
虽然XScale架构取得了巨大的成功,但是并没有使Intel盈利,Intel用长达八年的时间发现了一个事实,ARM的廉价授权策略并不能使处理器厂商获利,而最终获利者仅仅是ARM自身而已。更糟糕的是,Intel迎来了一个可怕的对手——AMD。AMD的异军突起使Intel的财务状况出现了严重的问题。
2006年,财报表现不佳的Intel开始了有史以来最大规模的裁员。并且做出了一个重大决定,将并不盈利的XScale处理器出售给马维尔(Marvell)。可悲的是,当时的马维尔并不需要XScale处理器,看重的仅仅是ARM指令集的完整授权。之后马维尔很快推出了自家的基于ARM指令集的处理器,XScale架构的命运终于走到了尽头。
此后,Intel全力对抗AMD,几年之后终于将AMD彻底击败。但是回头时却发现,ARM已经迅速发展壮大,并且控制了整个嵌入式处理器领域。这个不经意间培养的对手,让当下的Intel遭遇了空前的窘境。PC市场已经开始下滑,Intel必须找到新的增长点,才能保证其在移动互联网的大潮之下不被吞没,智能手机就是最好的切入点。决心重返嵌入式处理器领域的Intel与ARM联盟之间的战争由此拉开序幕。