quarta-feira, 1 de maio de 2013

AsyncTaskLoader

Olá povo,

Uma das coisas mais comuns em aplicações móveis é o acesso a servidores web através do protocolo HTTP. O Android obviamente nos permite esse tipo de comunicação de várias formas. Mas uma forma interessante foi introduzida na versão 3 da plataforma: os Loaders. Esse tipo de abordagem permite isolar a Activity da classe que está fazendo o download dos dados.
Um exemplo típico dessa abordagem é a utilização da classe AsyncTask - que eu sempre usei, e ainda uso - jutamente com um ProgressDialog. Normalmente o ProgressDialog era um atributo da AsyncTask  e no onPreExecute ele era exibido, sendo ocultado no onPostExecute. O problema dessa abordagem é que ao rotacionar a tela do aparelho, a Activity é recriada. Dessa forma, quando a AsyncTask terminava seu trabalho, a instância do Dialog armazenada ficava apontando para a instância da Activity que o tinha criado, gerando uma exceção em tempo de execução.

Com a chegada dos Fragments, é possível reter a instância do mesmo e ter um controle melhor sobre a rotação da tela (e outras mudanças de configuração). Mas a abordagem que eu achei interessante é a utilização da classe AsyncTaskLoader em conjunto com o LoadManager e a interface LoaderCallbacks. Vejamos o exemplo abaixo:
public class MainActivity 
  extends FragmentActivity 
  implements LoaderCallbacks<String> {

  ProgressDialog dialog;
  String json;
 
  private static final int MEU_LOADER = 0;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Recuperando o estado da Activity
    if (savedInstanceState != null) {
      json = savedInstanceState.getString("valores");
      atualizaTela();
    }

    // Essa classe gerencia todos os Loaders
    LoaderManager lm = getSupportLoaderManager();

    // Se o JSON ainda não foi baixado
    if (json == null) {
      // Exibe o dialog
      dialog = ProgressDialog.show(
        this, "Aguarde...", "Baixando tweets");

      // E inicializa o Loader (se ele já foi 
      // inicializado, ele apenas continuará)
      lm.initLoader(MEU_LOADER, null, this);
    }
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    // Se estiver exibindo o progress, remova-o 
    if (dialog != null && dialog.isShowing()) 
      dialog.dismiss();
  } 

  @Override
  protected void onSaveInstanceState(Bundle outState){
    super.onSaveInstanceState(outState);
    // Salvando o estado da Activity
    outState.putString("valores", json);
  }

  // Métodos da interface LoaderCallbacks -----------
  @Override
  public Loader<String> onCreateLoader(
    int id, Bundle args) {
    // Instancia e retorna a AsyncTaskLoader
    return new MinhaAsyncTask(this);
  }

  @Override
  public void onLoadFinished(Loader<String> loader, 
    String dados) {
    // Chamado quando o Loader termina seu trabalho
    // Aqui, atribuímos o resultado ao 
    // atributo json e ocultamos o dialog
    json = dados;
    atualizaTela();
    dialog.dismiss();
  }

  @Override
  public void onLoaderReset(Loader<String> loader) {
     // Chamado se o Loader for resetado
     Log.d("NGVL", "onLoaderReset");
  }

  // AsyncTaskLoader
  public static class MinhaAsyncTask 
    extends AsyncTaskLoader<String> {

    // O JSON baixado será armazenado aqui para ser 
    // repassado para Activity
    String data;

    public MinhaAsyncTask(Context context) {
      super(context);
    }

    @Override
    protected void onStartLoading() {
      // Se não baixou os dados, faça agora!
      if (data == null) {
        forceLoad();

      // Se já baixou, apenas entregue o resultado 
      } else {
        deliverResult(data);
      }
    }

    @Override
    public String loadInBackground() {
      // Nesse método será feito o download do JSON
      return downloadJSON();
    }
  }
}
O código acima está todo comentado. Então vou focar nos detalhes que devem ser observados.
O primeiro ponto é utilizar as classes do pacote android.support.v4.* pois o conceito de Loaders só surgiu no Honeycomb, então utilizei aqui a API de compatibilidade para que esse código execute sem problemas nas versões anteriores ao Android 3. O segundo ponto interessante é que, com essa abordagem o download não é reiniciado quando a Activity é recriada.
Outro detalhe é que, caso você queira chamar o loader novamente, você deve usar o método restartLoader e não o initLoader. E se quiser passar parâmetros para o Loader, pode usar um objeto Bundle e passá-lo como o segundo argumento desses métodos.
getSupportLoaderManager().restartLoader(
  MEU_LOADER, null, this);
Os métodos downloadJSON() e atualizaTela() devem ser implementados por você :) para baixar o JSON desejado e atualizar a tela da maneira apropriada.
Abaixo eu coloquei um exemplo desses dois métodos que baixa o JSON de uma busca no Twitter e exibe os textos dos Tweets em uma ListView.
private void atualizaLista() {
  if (json == null) return;
  try {
    JSONObject jsonObj = new JSONObject(json);
    JSONArray jsonResults = 
      jsonObj.getJSONArray("results");
   
    List<String> texts = new ArrayList<String>();
    for (int i = 0; i < jsonResults.length(); i++) {
      JSONObject result = jsonResults.getJSONObject(i);
      texts.add(result.getString("text"));
    }
   
    ListView list = (ListView)
      findViewById(R.id.ListView1);

    list.setAdapter(new ArrayAdapter<String>(this, 
      android.R.layout.simple_list_item_1, texts));
   
  } catch (JSONException e) {
    e.printStackTrace();
  }
}
 
private static String downloadJSON() {
  try {
    URL url = new URL(
      "http://search.twitter.com/search.json?q=jctransito");
    HttpURLConnection conexao = (HttpURLConnection)
      url.openConnection();
    conexao.connect();
   
    InputStream is = conexao.getInputStream();
    BufferedReader reader = new BufferedReader(
      new InputStreamReader(is));

    String s = reader.readLine();
    return s;
   
  } catch (Exception e) {
    e.printStackTrace();
  }
  return null;
}
Não esqueça de adicionar a permissão de INTERNET no AndroidManifest.xml.

Com abordagem acima, mesmo ao girar o aparelho, o download continuará, e caso não tenha terminado quando a Activity carregar, o ProgressDialog será exibido novamente.

Qualquer dúvida, deixem seus comentários.

4br4ç05,
nglauber

Referências:
http://developer.android.com/reference/android/app/LoaderManager.html
http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html
http://developer.android.com/reference/android/content/AsyncTaskLoader.html

sexta-feira, 12 de abril de 2013

Drag and Drop no Android

Olá povo,

Desde a versão 3 (API Level 11) o Android conta com uma API de Drag and Drop que facilita para o desenvolvedor a implementação da famosa ação de "arrastar e soltar". Nesse post, que foi baseado no texto orginal de Lars Vogel, vou mostrar um exemplo simples de como usar esse recurso na sua aplicação.

Para começar, crie um novo projeto Android e certifique-se de estar usando a API Level 11 ou superior. O projeto constará basicamente de uma tela com 4 LinearLayouts com uma ImageView em cada um deles. A idéia é que a ImageView de cada LinearLayout possa ser arrastada para outro LinearLayout.

Vamos começar criando a pasta res/drawable, onde vamos adicionar dois XMLs: o primeiro servirá de background normal dos LinearLayouts citados anteriormente, enquanto que o segundo será usado de background para quando estivermos arrastando a ImageView por sobre o LinearLayout.

O primeiro arquivo será o bg.xml
<shape 
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="rectangle" >

  <stroke
    android:width="2dp"
    android:color="#FFFFFFFF" />

  <gradient
    android:angle="225"
    android:endColor="#DD2ECCFA"
    android:startColor="#DD000000" />

  <corners
    android:bottomLeftRadius="7dp"
    android:bottomRightRadius="7dp"
    android:topLeftRadius="7dp"
    android:topRightRadius="7dp" />
</shape> 
O arquivo bg_over.xml é idêntico ao primeiro, a única mudança é a propriedade stroke color. Ela faz com que a cor da borda fique vermelha.
<shape 
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="rectangle" >

  <stroke
    android:width="2dp"
    android:color="##FFFF0000" />

  <gradient
    android:angle="225"
    android:endColor="#DD2ECCFA"
    android:startColor="#DD000000" />

  <corners
    android:bottomLeftRadius="7dp"
    android:bottomRightRadius="7dp"
    android:topLeftRadius="7dp"
    android:topRightRadius="7dp" />
</shape> 
O arquivo de layout da aplicação ficará como abaixo:
<TableLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/layoutRoot"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical" >
  <TableRow>
    <LinearLayout
      android:id="@+id/topleft"
      android:layout_width="0dp"
      android:layout_height="200dp"
      android:layout_weight="1"
      android:background="@drawable/bg" >
      <ImageView
        android:id="@+id/myimage1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher" />
    </LinearLayout>
    <LinearLayout
      android:id="@+id/topright"
      android:layout_width="0dp"
      android:layout_height="200dp"
      android:layout_weight="1"
      android:background="@drawable/bg" >
      <ImageView
        android:id="@+id/myimage2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher" />
    </LinearLayout>
  </TableRow>
  <TableRow>
    <LinearLayout
      android:id="@+id/bottomleft"
      android:layout_width="0dp"
      android:layout_height="200dp"
      android:layout_weight="1"
      android:background="@drawable/bg" >
      <ImageView
        android:id="@+id/myimage3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher" />
    </LinearLayout>
    <LinearLayout
      android:id="@+id/bottomright"
      android:layout_width="0dp"
      android:layout_height="200dp"
      android:layout_weight="1"
      android:background="@drawable/bg" >

      <ImageView
        android:id="@+id/myimage4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher" />
    </LinearLayout>
  </TableRow>
</TableLayout>
O Layout não tem nada de especial. Os LinearLayouts topleft, topright, bottomleft e bottomright servirão de containers onde poderemos arrastar e soltar as ImageViews myimage1, myimage2, myimage3 e myimage4. Vamos agora para o código da Activity.
public class MainActivity extends Activity 
  implements OnTouchListener, OnDragListener {
 
  Drawable enterShape;
  Drawable normalShape;
 
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  
    enterShape = getResources().
      getDrawable(R.drawable.bg_over);
    normalShape = getResources().
      getDrawable(R.drawable.bg);
  
    findViewById(R.id.myimage1).
      setOnTouchListener(this);
    findViewById(R.id.myimage2).
      setOnTouchListener(this);
    findViewById(R.id.myimage3).
      setOnTouchListener(this);
    findViewById(R.id.myimage4).
      setOnTouchListener(this);
  
    findViewById(R.id.topleft).
      setOnDragListener(this);
    findViewById(R.id.topright).
      setOnDragListener(this);
    findViewById(R.id.bottomleft).
      setOnDragListener(this);
    findViewById(R.id.bottomright).
      setOnDragListener(this);
  }

  public boolean onTouch(View view, MotionEvent me) {
    int action = me.getAction(); 
    if (action == MotionEvent.ACTION_DOWN) {
      ClipData data = ClipData.newPlainText("", "");
      DragShadowBuilder shadowBuilder = 
        new View.DragShadowBuilder(view);

      view.startDrag(data, shadowBuilder, view, 0);
      view.setVisibility(View.INVISIBLE);
      return true;
    }
    return false;
  }

  @Override
  public boolean onDrag(View v, DragEvent event) {
    switch (event.getAction()) {
    case DragEvent.ACTION_DRAG_ENTERED:
      // Ao entrar na área que pode fazer o drop
      v.setBackgroundDrawable(enterShape);
      break;
    case DragEvent.ACTION_DRAG_EXITED:
      // Ao sair da área que pode fazer o drop
      v.setBackgroundDrawable(normalShape);
      break;
    case DragEvent.ACTION_DROP:
      // Ao fazer o drop
      View view = (View) event.getLocalState();
      ViewGroup owner = (ViewGroup) view.getParent();
      owner.removeView(view);
      LinearLayout container = (LinearLayout) v;
      container.addView(view);
      view.setVisibility(View.VISIBLE);
      break;
    case DragEvent.ACTION_DRAG_ENDED:
      // Ao terminar de arrastar
      v.setBackgroundDrawable(normalShape);
      View view2 = (View) event.getLocalState();
      view2.setVisibility(View.VISIBLE);
    default:
      break;
    }
    return true;
  }
}
O código é relativamente simples e vou dar atenção aos principais pontos do drag and drop. Nossa Activity implementa duas interfaces: OnTouchListener e OnDragListener. A primeira tem a implementação no método onTouch e a segunda no onDrag. No onCreate, chamamos setOnTouchListener para as quatro ImageViews declaradas no arquivo de Layout, e logo em seguida chamamos o setOnDragListener para os LinearLayouts que servirão de container para soltarmos a ImageView dentro.

No método onTouch é onde começará o processo de drag (arrastar), nesse momento verificamos se a ação de touch é ACTION_DOWN, o que quer dizer que o dedo está pressionado sobre a ImageView.  Em caso positivo, criamos um objeto ClipData que permite transportar alguma informação junto com o objeto que está sendo arrastado. Já o objeto DragShadowBuilder serve para criar uma cópia da ImageView que será arrastada com o efeito de transparência. Para definitivamente iniciarmos o processo de arrastar, chamamos o método startDrag passando os objetos citados anteriormente juntamente com a View que disparou o evento, que no nosso caso, é uma ImageView. Por fim, deixamos a View invisível.

Já a ação de drop (soltar) é feita no método onDrag que é chamado algumas vezes com ações diferentes. Esse método é chamado enquanto a ImageView está sendo arrastada (e ao ser solta) por sobre o LinearLayout. Ao entrar na área que podemos soltar o ImageView, esse método é chamado com a ação será ACTION_DRAG_ENTERED, nesse caso, apenas mudamos o background do LinearLayout. Fazemos o inverso ao sair da área onde não podemos mais soltar a ImageView, onde a ação será ACTION_DRAG_EXITED. Já o ato de soltar propriamente dito é feito quando a ação é igual a ACTION_DROP, nesse momento realizamos as seguintes tarefas: obtemos a ImageView real que estamos arrastando através do método getLocalState(); pegamos o LinearLayout onde ela está contida com o método getParent(); removemos a ImageView do LinearLayout anterior; adicionamos no novo LinearLayout (o parâmetro v, indica o LinearLayout onde estamos soltando a ImageView); e deixamos a ImageView visível. A ação ACTION_DRAG_ENDED acontece quando todo o processo de Drag&Drop termina, nesse momento redefinimos o background e tornamos a ImageView visível novamente.
Abaixo podemos ver a aplicação em execução.
Qualquer dúvida, deixem seus comentários.

4br4ç05,
nglauber

quarta-feira, 3 de abril de 2013

Jornada Acadêmica Unibratec 2013.1

Olá povo,

Nos últimos dias 2 e 3 de Abril aconteceu mais uma Jornada Acadêmica da Unibratec. Como já é de costume, ministrei uma palestra, dessa vez com o título "Android e iOS: o que eles tem de diferente... ou não" em dois dias de sala lotada. Aproveito para agradecer a presença de todos.
Na oportunidade, falei sobre as diferenças e semelhanças das plataformas do Google e da Apple. Ao final da palestra, desenvolvemos uma aplicação simples em ambas as plataformas.

Os slides da apresentação estão disponíveis abaixo.


4br4ç05,
nglauber

sexta-feira, 22 de março de 2013

iOS: Dicas 3

Olá povo,

Quem está começando com o desenvolvimento iOS pode ficar um pouco perdido com a quantidade de novos recursos que aparecem a cada versão, principalmente se estiver usando livros e/ou cursos "antigos" (1 ano atrás é antigo sim :). Tendo em vista esse cenário, Stuart Hall deu as seguintes dicas pra quem estiver começando agora com programação para os dispositivos da Apple.

Esse post foi enviado para mim por Eric Cavalcanti e é praticamente uma tradução desse post aqui.

Use ARC!
ARC é incrível, ele remove muito da complexidade de gerenciamento de memória que tínhamos de lidar anteriormente. Apesar de ser importante entender o gerenciamento de memória, o ARC torna sua vida muito mais fácil.
Desenvolvedores mais experientes relutam em usá-lo, pois querem ter esse controle da alocação e liberação de memória. Mas como muitas bibliotecas populares passaram a usar ARC, não "bata o pé" e aproveite os benefícios do ARC.

Use Blocks
Blocos são impressionantes, o código fica menor e mais claro. Várias partes da API da própria Apple já usam esse recurso. Se você não conhece blocks, dê uma olhada nesse post aqui.
Há momentos em que os delegates/protocols ou NSNotifications fazem sentido, mas os blocks devem ser sua primeira opção.

Esqueça as Threads! Use GDC.
Não sei quem disse essa frase, mas ela é a mais pura verdade:
"A programmer had a problem, so he used threads, then he had two"

O GCD (Grand Central Dispatch) tornou a vida muito mais fácil, podemos fazer uma requisição em segundo plano para não travar a UI e depois podemos atualizá-la:
dispatch_async(
  dispatch_get_global_queue(
    DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
      ^(void) {
        // Código em background
        dispatch_async(dispatch_get_main_queue(), 
          ^(void) {
             // Atualize a UI
           }
        );
      }
);

Singletons com GDC
Como o Objective-C não tem o conceito de construtores, podemos usar o GDC para criar singletons.
+ (MinhaClasse *)sharedInstance {
  static MinhaClasse *_shared = nil;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    _shared = [[MinhaClasse alloc] init];
  });   
  return _shared;
}

StoryBoards são para protótipos
Na minha opinião os benefícios dos Storyboards não compensam, principalmente se você estiver fazendo mais que um projeto básico. Essa é a minha opinião, algumas pessoas amam Storyboards.
Para trabalhar em projetos com uma equipe de desenvolvimento, imagine você precise fazer merge de código de um StoryBoard usando SVN (ou até mesmo GIT). Pode ser traumático!

Internacionalize sua aplicação
Tenha em mente que sua aplicação poderá rodar em todos os países do mundo. Então prepare-a para rodar em vários idiomas. Eu fiz um vídeo que mostra como fazer internacionalização no iOS aqui.

Analise!
O menu Product > Analize exibe possíveis problemas no seu código. Achei ele muito bacana, principalmente em projetos médio/grandes.

Ame o StackOverflow
Há um monte de ótimos desenvolvedores iOS no Stack Overflow, e as chances de que eles tenham resolvido o seu problema são bem grandes. Por favor, procure antes de fazer uma pergunta, a maioria já foi respondida.

4br4ç05,
nglauber


sexta-feira, 1 de março de 2013

Artigo "Push Notifications no Android"

Olá povo,

A revista Java Magazine traz em sua edição 113 mais um artigo de minha autoria para a publicação da DevMedia. A matéria entitulada "Push Notifications no Android" mostra como utilizar o serviço de envio de mensagens da nuvem para dispositivos Android através da  Google Cloud Messaging ou simplesmente GCM.

Neste artigo mostro como enviar informações de uma aplicação web para dispositivos Android usando a API do GCM. Uma ótima opção para desenvolvedores que querem promover a integração de aplicações web com dispositivos móveis.

O texto vem para complementar o artigo de C2DM que foi publicado na edição 107.

Espero que gostem.

4br4ç05,
nglauber

sexta-feira, 22 de fevereiro de 2013

Android: Dicas 8

Olá povo,

Mais um post da série "Dicas de Android", aproveitem! E como sempre, qualquer dúvida ou sugestão deixem seus comentários.

Dica 1 - Crash Report

Essa dica veio de Charles Alves do Curso de Android EAD do CESAR.edu. É possível enviar relatórios de erro da sua aplicação para onde o desenvolvedor desejar através do ACRA (https://github.com/ACRA/acra), por padrão, ele envia para um formulário no google docs.

Dica 2 - Verificar recursos do aparelho.

Através da classe PackageManager podemos verificar se um aparelho conta com um determinado recurso de hardware, como câmera, wi-fi, etc.

PackageManager pm = getPackageManager();
boolean temCamera = 
  pm.hasSystemFeature(
    PackageManager.FEATURE_CAMERA);
boolean temWiFiDirect = 
  pm.hasSystemFeature(
    PackageManager.FEATURE_WIFI_DIRECT);
boolean temScreenPortrait = 
  pm.hasSystemFeature(
    PackageManager.FEATURE_SCREEN_PORTRAIT);

Dica 3 - Mockups pra Android (Dica de Eric Cavalcanti)

Uma ótima ferramenta de prototipagem para Android é o Pencil (http://pencil.evolus.vn). Vale a pena conferir.

Dica 4 - Obtendo o tamanho da tela
Muitas vezes é necessário obter o tamanho da tela. Podemos fazer isso através da classe Display. Ela é retornada pela classe WindowManager que é um serviço do sistema.

Display display = ((WindowManager) 
  getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
int width = display.getWidth();  
int height = display.getHeight();

Dica 5 - Rotação do Emulador 2.3
Um "problema" que eu sempre tinha no emulador do 2.3, era que quando eu girava o emulador para landscape e voltava para portrait, o mesmo continuava em landscape. Para contornar isso, acesse a opção Menu/Settings/Screen e desabilite a opção Autorotate.

Dica 6 - Invertendo os itens da ListView
Podemos fazer com que os itens de uma ListView começem de baixo, basta usar a propriedade android:stackFromBottom="true".

Dica 7 - PopupWindow
Só suportado no Android 3.0 (API Level 11)
public void showPopup(View v) {
    PopupMenu popup = new PopupMenu(this, v);
    MenuInflater inflater = popup.getMenuInflater();
    inflater.inflate(R.menu.actions, popup.getMenu());
    popup.show();
}

Dica 8 - Exibir um vídeo
Dica de Tiago Gomes, aluno da Unibratec. Tocar vídeo da pasta res/raw

VideoView video = (VideoView) 
  findViewById(R.id.videoView1);
Uri uri = Uri.parse("android.resource://" + 
  getPackageName() + "/raw/arquivo_video");
video.setVideoURI(uri);
video.requestFocus();
video.start();

Dica 9 - API para gráficos de "pizza"
Dúvida de Rodrigo Bezerra. Eu nunca usei, mas aparentemente funciona :)
http://www.achartengine.org/

4br4ç05,
nglauber

sexta-feira, 15 de fevereiro de 2013

iOS: Dicas 2

Olá povo,

Esse post vai em homenagem a minha turma do Curso de iOS à distância que ministrei no CESAR.edu. Foram deles as dúvidas abaixo que resolvi compartilhar com vocês.

Dica 1 - Adicionando UITableView ao UIAlertView
Podemos adicionar qualquer UIView dentro de um UIAlertView. Basta usar o método addSubView e posicioná-la da maneira que deseja. O que achei "feio" aqui é que para determinar o tamanho do alert setamos o texto dele com "\n". Poderíamos utilizar o método initWithFrame, mas achei o código ainda mais complexo (embora mais preciso em termos de tamanho).

UITableView *table = 
  [[UITableView alloc] 
    initWithFrame:CGRectMake(10, 50, 265, 100)];    
table.dataSource = self;
table.delegate = self;
    
UIAlertView *alert = [[UIAlertView alloc] 
  initWithTitle:@"Escolha uma opção"
  message:@"\n\n\n\n\n" 
  delegate:self 
  cancelButtonTitle:@"OK" 
  otherButtonTitles:nil, nil];
    
[alert addSubview:table];
alert.autoresizesSubviews = YES;
[alert show];

Tem uma opção interessante aqui também.

Dica 2 - Desabilitando um segmento do UISegmentedControl
Essa foi simples de achar, mas na aula passou desapercebido.

[_meuSegmentedControl 
  setEnabled:NO forSegmentAtIndex:0];

Dica 3 - Definir o badge da aplicação
O badge nada mais é do que o número que aparece em cima do ícone da aplicação, por exemplo quanto temos chamadas não atendidas e/ou mensagens recebidas.

[[UIApplication sharedApplication] 
  setApplicationIconBadgeNumber:12];

Dica 4 - Adicionar View ao teclado
Ao invés de criar a view no código, você pode adicionar a mesma no XIB da tela e setar a propriedade inputAccessoryView. Para exemplificar, adicionei uma Toolbar ao XIB e crie um IBOutlet para ela.
@interface NGViewController : UIViewController
@property (weak, nonatomic) 
  IBOutlet UITextField *txtSobrenome;
@property (weak, nonatomic) 
  IBOutlet UIToolbar *minhaBarra;
@end
Depois é só colocar isso no viewDidLoad
[_txtSobrenome setInputAccessoryView:_minhaBarra];


Dica 5 - Ocultar teclado virtual
Sempre xingava o iOS por ter que ocultar o teclado via código. Mas achei a melhor maneira para ocultar o teclado. É só usar o método touchesBegan:withEvent da classe UIRespoder (super classe de UIView e UIViewController)  e chamar o método endEditing da UIView.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
}
Independente da quantidade de UITextFields, o teclado vai sempre desaparecer.

Dicas 6 - Obtendo a orientação
Uma das melhores maneiras de obter a orientação do dispositivo é a abaixo:

// Verifica se é portrait ou portrait upsidedown
if (UIDeviceOrientationIsPortrait(
      [[UIApplication sharedApplication] 
        statusBarOrientation])){
}

Essa abordagem resolve alguns problemas que já tive. Por exemplo, quando o telefone está sobre a mesa, o método [[UIDevice currentDevice]orientation] retorna a orientação UIDeviceOrientationFaceUp (com o display para cima), enquanto que o método acima retorna a orientação da barra de status do aparelho e não do aparelho em si.

Qualquer dúvida (ou sugestão), deixem seus comentários,

4br4ç05
nglauber