KEMBAR78
MDSD for iPhone and Android | PDF
Modellgetriebene App-Entwicklung
für iPhone und Android
Heiko Behrens, itemis
Regionalgruppe Hamburg der GI
Hamburg 24.09.2010
@HBehrens
http://mobile.itemis.de
Dienstag, 28. September 2010
Modellgetriebene App-Entwicklung
für iPhone und Android
Dienstag, 28. September 2010
Modellgetriebene App-Entwicklung
für iPhone und Android
Dienstag, 28. September 2010
/ soft·ware de·vel·op·ment / n.
the set of activities that results in
software products. ~ may include
research, new development,
modification, reuse, maintenance,
or any other activities that result in
software products.
Dienstag, 28. September 2010
Typical Situations
in
Software Development
Dienstag, 28. September 2010
Boring code
Dienstag, 28. September 2010
Accidental complexity
Dienstag, 28. September 2010
Wrong level of abstraction
Dienstag, 28. September 2010
Anatomy of Modern Software
schematic code (manually written)
Libraries
Frameworks
manually written
code
Dienstag, 28. September 2010
Dienstag, 28. September 2010
package templates;
import java.util.*;
import java.io.Serializable;
import javax.persistence.*;
@SuppressWarnings("serial")
@Entity
public class Customer implements Serializable {
	 private Long id;
	 private String name;
	 private Address address;
	 private Set<Order> orders = new HashSet<Order>();
	 // No-arg constructor
	 public Customer() {
	 }
	 @Id
	 public Long getId() {
	 	 return id;
	 }
	 public void setId(Long id) {
	 	 this.id = id;
	 }
	 public String getName() {
	 	 return name;
	 }
	 public void setName(String name) {
	 	 this.name = name;
	 }
	 public Address getAddress() {
	 	 return address;
	 }
	 public void setAddress(Address address) {
	 	 this.address = address;
	 }
	 @OneToMany
	 public Collection<Order> getOrders() {
	 	 return orders;
	 }
	 public void setOrders(Set<Order> orders) {
	 	 this.orders = orders;
	 }
}
Dienstag, 28. September 2010
package templates;
import java.io.Serializable;
import java.util.*;
import javax.persistence.*;
@SuppressWarnings("serial")
@Entity
public class Customer implements Serializable {
	 private Long id;
	 private String name;
	 private Address address;
	 private Set<Order> orders = new HashSet<Order>();
	 // No-arg constructor
	 public Customer() {
	 }
	 @Id
	 public Long getId() {
	 	 return id;
	 }
	 public void setId(Long id) {
	 	 this.id = id;
	 }
	 public String getName() {
	 	 return name;
	 }
	 public void setName(String name) {
	 	 this.name = name;
	 }
	 public Address getAddress() {
	 	 return address;
	 }
	 public void setAddress(Address address) {
	 	 this.address = address;
	 }
	 @OneToMany
	 public Collection<Order> getOrders() {
	 	 return orders;
	 }
	 public void setOrders(Set<Order> orders) {
	 	 this.orders = orders;
	 }
}
Dienstag, 28. September 2010
Common Approaches
to
Avoid Redundancy
Dienstag, 28. September 2010
Wizards
Dienstag, 28. September 2010
This wizard whips up a
complete and running
legacy application with
just a single click.
Dienstag, 28. September 2010
Designers
Dienstag, 28. September 2010
Model-Driven
Software Development
Dienstag, 28. September 2010
Raise the level
of abstraction
where possible
and generate
code wisely.
Dienstag, 28. September 2010
One cannot
abstract away
everything.
Manual code is
great for all the
special cases and
details.
Dienstag, 28. September 2010
Use the best of both worlds at the same time.
Dienstag, 28. September 2010
Dienstag, 28. September 2010
Suppose...
Dienstag, 28. September 2010
You’d want to core an apple...
Dienstag, 28. September 2010
... for your kids.
Dienstag, 28. September 2010
Right tool for the job
?
Dienstag, 28. September 2010
Your trusty swiss army knife!
Dienstag, 28. September 2010
Suppose...
Dienstag, 28. September 2010
You’d want to core a few more apples...
Dienstag, 28. September 2010
... for an apple cake.
Dienstag, 28. September 2010
Still the best tool for the job?
Dienstag, 28. September 2010
Better use this one
Dienstag, 28. September 2010
...and this one
Dienstag, 28. September 2010
... a DSL is ...
Dienstag, 28. September 2010
A specific tool
for a specific job
Dienstag, 28. September 2010
A specific tool
for a specific job
Dienstag, 28. September 2010
Use DSLs to describe the world
Dienstag, 28. September 2010
select name, salary
from employees
where salary > 2000
order by salary
^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}$
Dienstag, 28. September 2010
http://mobl-lang.org/
http://code.google.com/p/iphonical/
http://code.google.com/p/applause/
applause
iPhonical
mobl
Dienstag, 28. September 2010
entity Vortrag {
	 String titel
	 String untertitel
	 String sprecher
	 String beschreibung
}
contentprovider AllVortragItems
	 returns Vortrag[]
	 fetches XML
	 	 from "http://spreadsheets.google.com/feeds/list/.../public/values"
	 	 selects "feed.entry"
tableview VortragListe(Vortrag[] items) {
	 title= "Vorträge"
	 section {
	 	 cell Subtitle foreach items as i {
	 	 	 text= i.titel
	 	 	 details= i.untertitel
	 	 	 action= VortragDetailsView( i )
	 	 }
	 }
}
tabbarApplication itemisApp {
	 button {
	 	 title= "Vorträge"
	 	 icon= "66-microphone.png"
	 	 view= VortragListe( AllVortragItems() )
	 }
	 button {
	 	 title= "Referenten"
	 	 icon= "person.png"
	 	 view= SprecherListe( AllSprecherItems() )
	 }
}
Entities & Data Access
Views & Actions
Navigation
Dienstag, 28. September 2010
... for building DSLs?
Why not use a DSL...
Dienstag, 28. September 2010
http://www.eclipse.org/Xtext/
@xtext
Dienstag, 28. September 2010
Superclass
Subclass Class
ECore meta model
LL(*) Parser Editor
Model
G
r
a
m
m
a
r
Generator
Runtime
Dienstag, 28. September 2010
Grammar (similar to EBNF)
grammar org.xtext.example.Entity with org.eclipse.xtext.common.Terminals
generate entity "http://www.xtext.org/example/Entity"
Model:
(types+=Type)*;
Type:
TypeDef | Entity;
TypeDef:
"typedef" name=ID ("mapsto" mappedType=JAVAID)?;
JAVAID:
name=ID("." ID)*;
Entity:
"entity" name=ID ("extends" superEntity=[Entity])?
"{"
(attributes+=Attribute)*
"}";
Attribute:
type=[Type] (many?="*")? name=ID;
Dienstag, 28. September 2010
grammar org.xtext.example.Entity
with org.eclipse.xtext.common.Terminals
generate entity
"http://www.xtext.org/example/Entity"
Model:
(types+=Type)*;
Type:
TypeDef | Entity;
TypeDef:
"typedef" name=ID
("mapsto" mappedType=JAVAID)?;
JAVAID:
name=ID("." ID)*;
Entity:
"entity" name=ID
("extends" superEntity=[Entity])?
"{"
(attributes+=Attribute)*
"}";
Attribute:
type=[Type] (many?="*")? name=ID;
entity
Model
*
name: EString
Type
types
TypeDef Entity
name: EString
JAVAID
superEntity
mappedType
name: EString
many: EBoolean
Attribute
attributes
type
Meta model inference
Dienstag, 28. September 2010
Let’s build a DSL
for Mobile Apps
Dienstag, 28. September 2010
Dienstag, 28. September 2010
Anatomy of an iPhone app
Table view
View title
Tab bar
Tab bar button
Name
Image
Speaker
Title
Location
Session
Entity
Data Provider
Table cell
Dienstag, 28. September 2010
Mapping concepts
Table view
View title
Table cell
Tab bar
Tab bar button
Entity
Data Provider
tabbarApplication itemisApp {
	 button {
	 	 title= "Blog"
	 	 icon= "08-chat.png"
	 	 view= BlogList( Blogposts() )
	 }
	 button {
	 	 title= "Talks"
	 	 icon= "66-microphone.png"
	 	 view= VortragListe( AllVortragItems() )
	 }
	 button {
	 	 title= "Speakers"
	 	 icon= "person.png"
	 	 view= SprecherListe( AllSprecherItems() )
	 }
}
Dienstag, 28. September 2010
Mapping concepts
Table view
View title
Table cell
Tab bar
Tab bar button
Entity
Data Provider
entity BlogItem {
	 String title
	 String author
	 String link
	 String description
	 String pubDate
	 BlogItem subItem
}
entity Sprecher {
	 String name
	 String beschreibung
	 String email
	 String blog
	 String fotourl
	 String vortraege
}
entity Vortrag {
	 String titel
	 String untertitel
	 String sprecher
	 String beschreibung
	 String zeit
	 Vortrag fortsetzung
}
Dienstag, 28. September 2010
Mapping concepts
Table view
View title
Table cell
Tab bar
Tab bar button
Entity
Data Provider
contentprovider Blogposts
	 returns BlogItem[]
	 fetches XML
	 	 from "http://blogs.itemis.de/?showfeed=1"
	 	 selects "rss.channel.item"
	
contentprovider AllVortragItems
	 returns Vortrag[]
	 fetches XML
	 	 from "http://spreadsheets.google.com/feeds/
list/0Au3-oaNYhfPIdEpRQWxpZnJyX2JCNUdtT1Z4M1B4SkE/1/
public/values"
	 	 selects "feed.entry"
Dienstag, 28. September 2010
Mapping concepts
Table view
View title
Table cell
Tab bar
Tab bar button
Entity
Data Provider tableview BlogList(BlogItem[] items) {
	 title= "itemis blog"
	 section {
	 	 cell Subtitle foreach items as i {
	 	 	 text= i.author
	 	 	 details= i.title
	 	 	 image= ("http://blogs.itemis.de/wp-content/
themes/itemis-WP-Theme/photos/" urlconform(i.author)
".jpg")
	 	 	 action= BlogDetails(i)
	 	 }
	 }
}
Dienstag, 28. September 2010
Type safe
Produces any
kind of text
Can run standalone
(ANT / Maven)
Debugger
Profiler
Eclipse-based
Editor
Protected regions
Cartridges
Outlets
Polymorphism
Dienstag, 28. September 2010
tableview SpeakerList(
Speaker[] speakers)
{
title= "Speakers"
section
{
cell Default foreach
speakers as speaker
{
text= speaker.name
image= speaker.smallImageURL
action= SpeakerDetails
(SpeakerById(
speaker.speakerId))
}
}
}
Mapping concepts to code
Dienstag, 28. September 2010
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
!
id item = [self.items objectAtIndex: indexPath.row];
!
UITableViewCell *cell =
[self cellDefaultForTableView:tableView];
cell.textLabel.text = [item valueForKeyPath:@"name"];
!
NSString *imageURL = [item valueForKeyPath:@"fotourl"];
cell.imageView.image = [self getImage: imageURL
withLoadingImage:@"personLoading.png"
andErrorImage:@"personUnknown.png"];
return cell;
}
Cell Rendering
Dienstag, 28. September 2010
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
!
id item = [self.items objectAtIndex: indexPath.row];
!
UITableViewCell *cell =
[self cellDefaultForTableView:tableView];
cell.textLabel.text = [item valueForKeyPath:@"name"];
!
NSString *imageURL = [item valueForKeyPath:@"fotourl"];
cell.imageView.image = [self getImage: imageURL
withLoadingImage:@"personLoading.png"
andErrorImage:@"personUnknown.png"];
return cell;
}
Cell Rendering
tableview SpeakerList(
Speaker[] speakers)
{
title= "Speakers"
section
{
cell Default foreach
speakers as speaker
{
text= speaker.name
image= speaker.smallImageURL
action= SpeakerDetails
(SpeakerById(
speaker.speakerId))
}
}
}
Dienstag, 28. September 2010
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
id item = [self.items objectAtIndex: indexPath.row];
IPContentProvider *provider =
[IPSimpleContentProvider providerWithContent:item
andProviders:self.contentProvider.providers];
SprecherDetailsViewController *controller =
[[SprecherDetailsViewController alloc] init];
controller.contentProvider = provider;
[self.navigationController pushViewController:
controller animated: TRUE];
[controller release];
}
User Interaction
tableview SpeakerList(
Speaker[] speakers)
{
title= "Speakers"
section
{
cell Default foreach
speakers as speaker
{
text= speaker.name
image= speaker.smallImageURL
action= SpeakerDetails
(SpeakerById(
speaker.speakerId))
}
}
}
Dienstag, 28. September 2010
tableview SpeakerList(
Speaker[] speakers)
{
title= "Speakers"
section
{
cell Default foreach
speakers as speaker
{
text= speaker.name
image= speaker.smallImageURL
action= SpeakerDetails
(SpeakerById(
speaker.speakerId))
}
}
}
«DEFINE viewModule FOR SectionedView»
«FILE filenameModule()»
#import "«filenameHeader()»"
#import "NSObject+Applause.h"
«EXPAND imports»
@implementation «className()»
«EXPAND sectionCount»
«EXPAND sectionTitleHeader»
«EXPAND rowCounts»
«EXPAND cellDescriptions»
«EXPAND cellSelections»
«EXPAND staticData»
@end
«ENDFILE»
«ENDDEFINE»
Template Invocation
Dienstag, 28. September 2010
Demo
Dienstag, 28. September 2010
@HBehrens
http://HeikoBehrens.net
mobile.itemis.de
eclipse.org
code.google.com/p/applause
twitter
blog
consulting
Xtext/Xpand
applause
Dienstag, 28. September 2010

MDSD for iPhone and Android

  • 1.
    Modellgetriebene App-Entwicklung für iPhoneund Android Heiko Behrens, itemis Regionalgruppe Hamburg der GI Hamburg 24.09.2010 @HBehrens http://mobile.itemis.de Dienstag, 28. September 2010
  • 2.
    Modellgetriebene App-Entwicklung für iPhoneund Android Dienstag, 28. September 2010
  • 3.
    Modellgetriebene App-Entwicklung für iPhoneund Android Dienstag, 28. September 2010
  • 4.
    / soft·ware de·vel·op·ment/ n. the set of activities that results in software products. ~ may include research, new development, modification, reuse, maintenance, or any other activities that result in software products. Dienstag, 28. September 2010
  • 5.
  • 6.
  • 7.
  • 8.
    Wrong level ofabstraction Dienstag, 28. September 2010
  • 9.
    Anatomy of ModernSoftware schematic code (manually written) Libraries Frameworks manually written code Dienstag, 28. September 2010
  • 10.
  • 11.
    package templates; import java.util.*; importjava.io.Serializable; import javax.persistence.*; @SuppressWarnings("serial") @Entity public class Customer implements Serializable { private Long id; private String name; private Address address; private Set<Order> orders = new HashSet<Order>(); // No-arg constructor public Customer() { } @Id public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } @OneToMany public Collection<Order> getOrders() { return orders; } public void setOrders(Set<Order> orders) { this.orders = orders; } } Dienstag, 28. September 2010
  • 12.
    package templates; import java.io.Serializable; importjava.util.*; import javax.persistence.*; @SuppressWarnings("serial") @Entity public class Customer implements Serializable { private Long id; private String name; private Address address; private Set<Order> orders = new HashSet<Order>(); // No-arg constructor public Customer() { } @Id public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } @OneToMany public Collection<Order> getOrders() { return orders; } public void setOrders(Set<Order> orders) { this.orders = orders; } } Dienstag, 28. September 2010
  • 13.
  • 14.
  • 15.
    This wizard whipsup a complete and running legacy application with just a single click. Dienstag, 28. September 2010
  • 16.
  • 17.
  • 18.
    Raise the level ofabstraction where possible and generate code wisely. Dienstag, 28. September 2010
  • 19.
    One cannot abstract away everything. Manualcode is great for all the special cases and details. Dienstag, 28. September 2010
  • 20.
    Use the bestof both worlds at the same time. Dienstag, 28. September 2010
  • 21.
  • 22.
  • 23.
    You’d want tocore an apple... Dienstag, 28. September 2010
  • 24.
    ... for yourkids. Dienstag, 28. September 2010
  • 25.
    Right tool forthe job ? Dienstag, 28. September 2010
  • 26.
    Your trusty swissarmy knife! Dienstag, 28. September 2010
  • 27.
  • 28.
    You’d want tocore a few more apples... Dienstag, 28. September 2010
  • 29.
    ... for anapple cake. Dienstag, 28. September 2010
  • 30.
    Still the besttool for the job? Dienstag, 28. September 2010
  • 31.
    Better use thisone Dienstag, 28. September 2010
  • 32.
    ...and this one Dienstag,28. September 2010
  • 33.
    ... a DSLis ... Dienstag, 28. September 2010
  • 34.
    A specific tool fora specific job Dienstag, 28. September 2010
  • 35.
    A specific tool fora specific job Dienstag, 28. September 2010
  • 36.
    Use DSLs todescribe the world Dienstag, 28. September 2010
  • 37.
    select name, salary fromemployees where salary > 2000 order by salary ^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}$ Dienstag, 28. September 2010
  • 38.
  • 39.
    entity Vortrag { String titel String untertitel String sprecher String beschreibung } contentprovider AllVortragItems returns Vortrag[] fetches XML from "http://spreadsheets.google.com/feeds/list/.../public/values" selects "feed.entry" tableview VortragListe(Vortrag[] items) { title= "Vorträge" section { cell Subtitle foreach items as i { text= i.titel details= i.untertitel action= VortragDetailsView( i ) } } } tabbarApplication itemisApp { button { title= "Vorträge" icon= "66-microphone.png" view= VortragListe( AllVortragItems() ) } button { title= "Referenten" icon= "person.png" view= SprecherListe( AllSprecherItems() ) } } Entities & Data Access Views & Actions Navigation Dienstag, 28. September 2010
  • 40.
    ... for buildingDSLs? Why not use a DSL... Dienstag, 28. September 2010
  • 41.
  • 42.
    Superclass Subclass Class ECore metamodel LL(*) Parser Editor Model G r a m m a r Generator Runtime Dienstag, 28. September 2010
  • 43.
    Grammar (similar toEBNF) grammar org.xtext.example.Entity with org.eclipse.xtext.common.Terminals generate entity "http://www.xtext.org/example/Entity" Model: (types+=Type)*; Type: TypeDef | Entity; TypeDef: "typedef" name=ID ("mapsto" mappedType=JAVAID)?; JAVAID: name=ID("." ID)*; Entity: "entity" name=ID ("extends" superEntity=[Entity])? "{" (attributes+=Attribute)* "}"; Attribute: type=[Type] (many?="*")? name=ID; Dienstag, 28. September 2010
  • 44.
    grammar org.xtext.example.Entity with org.eclipse.xtext.common.Terminals generateentity "http://www.xtext.org/example/Entity" Model: (types+=Type)*; Type: TypeDef | Entity; TypeDef: "typedef" name=ID ("mapsto" mappedType=JAVAID)?; JAVAID: name=ID("." ID)*; Entity: "entity" name=ID ("extends" superEntity=[Entity])? "{" (attributes+=Attribute)* "}"; Attribute: type=[Type] (many?="*")? name=ID; entity Model * name: EString Type types TypeDef Entity name: EString JAVAID superEntity mappedType name: EString many: EBoolean Attribute attributes type Meta model inference Dienstag, 28. September 2010
  • 45.
    Let’s build aDSL for Mobile Apps Dienstag, 28. September 2010
  • 46.
  • 47.
    Anatomy of aniPhone app Table view View title Tab bar Tab bar button Name Image Speaker Title Location Session Entity Data Provider Table cell Dienstag, 28. September 2010
  • 48.
    Mapping concepts Table view Viewtitle Table cell Tab bar Tab bar button Entity Data Provider tabbarApplication itemisApp { button { title= "Blog" icon= "08-chat.png" view= BlogList( Blogposts() ) } button { title= "Talks" icon= "66-microphone.png" view= VortragListe( AllVortragItems() ) } button { title= "Speakers" icon= "person.png" view= SprecherListe( AllSprecherItems() ) } } Dienstag, 28. September 2010
  • 49.
    Mapping concepts Table view Viewtitle Table cell Tab bar Tab bar button Entity Data Provider entity BlogItem { String title String author String link String description String pubDate BlogItem subItem } entity Sprecher { String name String beschreibung String email String blog String fotourl String vortraege } entity Vortrag { String titel String untertitel String sprecher String beschreibung String zeit Vortrag fortsetzung } Dienstag, 28. September 2010
  • 50.
    Mapping concepts Table view Viewtitle Table cell Tab bar Tab bar button Entity Data Provider contentprovider Blogposts returns BlogItem[] fetches XML from "http://blogs.itemis.de/?showfeed=1" selects "rss.channel.item" contentprovider AllVortragItems returns Vortrag[] fetches XML from "http://spreadsheets.google.com/feeds/ list/0Au3-oaNYhfPIdEpRQWxpZnJyX2JCNUdtT1Z4M1B4SkE/1/ public/values" selects "feed.entry" Dienstag, 28. September 2010
  • 51.
    Mapping concepts Table view Viewtitle Table cell Tab bar Tab bar button Entity Data Provider tableview BlogList(BlogItem[] items) { title= "itemis blog" section { cell Subtitle foreach items as i { text= i.author details= i.title image= ("http://blogs.itemis.de/wp-content/ themes/itemis-WP-Theme/photos/" urlconform(i.author) ".jpg") action= BlogDetails(i) } } } Dienstag, 28. September 2010
  • 52.
    Type safe Produces any kindof text Can run standalone (ANT / Maven) Debugger Profiler Eclipse-based Editor Protected regions Cartridges Outlets Polymorphism Dienstag, 28. September 2010
  • 53.
    tableview SpeakerList( Speaker[] speakers) { title="Speakers" section { cell Default foreach speakers as speaker { text= speaker.name image= speaker.smallImageURL action= SpeakerDetails (SpeakerById( speaker.speakerId)) } } } Mapping concepts to code Dienstag, 28. September 2010
  • 54.
    - (UITableViewCell *)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ! id item = [self.items objectAtIndex: indexPath.row]; ! UITableViewCell *cell = [self cellDefaultForTableView:tableView]; cell.textLabel.text = [item valueForKeyPath:@"name"]; ! NSString *imageURL = [item valueForKeyPath:@"fotourl"]; cell.imageView.image = [self getImage: imageURL withLoadingImage:@"personLoading.png" andErrorImage:@"personUnknown.png"]; return cell; } Cell Rendering Dienstag, 28. September 2010
  • 55.
    - (UITableViewCell *)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ! id item = [self.items objectAtIndex: indexPath.row]; ! UITableViewCell *cell = [self cellDefaultForTableView:tableView]; cell.textLabel.text = [item valueForKeyPath:@"name"]; ! NSString *imageURL = [item valueForKeyPath:@"fotourl"]; cell.imageView.image = [self getImage: imageURL withLoadingImage:@"personLoading.png" andErrorImage:@"personUnknown.png"]; return cell; } Cell Rendering tableview SpeakerList( Speaker[] speakers) { title= "Speakers" section { cell Default foreach speakers as speaker { text= speaker.name image= speaker.smallImageURL action= SpeakerDetails (SpeakerById( speaker.speakerId)) } } } Dienstag, 28. September 2010
  • 56.
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath { id item = [self.items objectAtIndex: indexPath.row]; IPContentProvider *provider = [IPSimpleContentProvider providerWithContent:item andProviders:self.contentProvider.providers]; SprecherDetailsViewController *controller = [[SprecherDetailsViewController alloc] init]; controller.contentProvider = provider; [self.navigationController pushViewController: controller animated: TRUE]; [controller release]; } User Interaction tableview SpeakerList( Speaker[] speakers) { title= "Speakers" section { cell Default foreach speakers as speaker { text= speaker.name image= speaker.smallImageURL action= SpeakerDetails (SpeakerById( speaker.speakerId)) } } } Dienstag, 28. September 2010
  • 57.
    tableview SpeakerList( Speaker[] speakers) { title="Speakers" section { cell Default foreach speakers as speaker { text= speaker.name image= speaker.smallImageURL action= SpeakerDetails (SpeakerById( speaker.speakerId)) } } } «DEFINE viewModule FOR SectionedView» «FILE filenameModule()» #import "«filenameHeader()»" #import "NSObject+Applause.h" «EXPAND imports» @implementation «className()» «EXPAND sectionCount» «EXPAND sectionTitleHeader» «EXPAND rowCounts» «EXPAND cellDescriptions» «EXPAND cellSelections» «EXPAND staticData» @end «ENDFILE» «ENDDEFINE» Template Invocation Dienstag, 28. September 2010
  • 58.
  • 59.