Letölthető példaprogramok
Kattints a linkre a példaprogramok letöltéséhez!
Hello, World
Egyszerű c hello-world program, ami Objective-C ben is lefordul és működik.
hello.m
#import <stdio.h>
/*
gcc -o hello hello.m -I /GNUstep/System/Library/Headers \
-L /GNUstep/System/Library/Libraries -lobjc \
-lgnustep-base -fconstant-string-class=NSConstantString
*/
//szabvanyos c program => szabvanyos objective-c program
int main( int argc, const char *argv[] ) {
printf( "hello world\n" );
return 0;
}
Objektumokat használó hello world program.
A @"Hello, World!" egy Objective-C sztring objektumot hoz létre (automatikusan),
ami a program végén szabadul fel.
A <Foundation/Foundation.h> tartalmazza a szükséges osztálydefiniókat,
ezért importálni kell.
hellognustep.m
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
//utomatikus objektumfelszabaditashoz szukseges
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//log uzenet kiirasa a standard kimenetre
NSLog (@"Hello, World!");
//automatikus objektumfelszabaditas elvegzese
[pool drain];
return 0;
}
Boolean típus
Érdekesség: true és false helyett YES és NO használható.
boolean.m
#import <stdio.h>
#import <Foundation/Foundation.h>
int main( int argc, const char *argv[] ) {
//logikai változó létrehozása: BOOL tÃpus
//Lehetséges értékek: YES / NO
BOOL x = YES;
if (x) printf("Yes\n");
x = NO;
if (x==NO) printf("No\n");
//printf( " \n" );
return 0;
}
Osztályok, Kategóriák
Fejléc fájl - az osztály adattagjait és metódusdeklarációit tartalmazza.
Complex.h
#import <Foundation/NSObject.h>
//interface: adattagok, majd a megvalositott metodusok
@interface Complex: NSObject {
//lathatosag - protected az alapertelmezes is
@protected
double real;
double imaginary;
}
-(void) setReal: (double) a;
-(void) setImaginary: (double) b;
-(void) setReal: (double) a andImaginary: (double) b;
-(double) real;
-(double) imaginary;
-(void) print;
@end
Az osztály metódusainak megvalósítása megvalósítása .m kiterjesztésű fájlokba kerül.
Complex.m
#import "Complex.h"
#import "ComplexOperations.h"
#import <stdio.h>
@implementation Complex
// - : objektum metodus
//(void) : void visszateresi ertek
-(void) print {
printf( " %f + i * %f ", real, imaginary );
}
//(double) a
//double parameter, neve a
-(void) setReal: (double) a {
real = a;
}
-(void) setImaginary: (double) b {
imaginary = b;
}
-(double) real {
return real;
}
-(double) imaginary {
return imaginary;
}
//Metodus tobb parameterrel
-(void) setReal: (double) a andImaginary: (double) b {
//Az objektum onmaganak is kuldhet uzenetet!
[self setReal: a];
[self setImaginary: b];
}
@end
Az osztályokat kibővíthetjük kategóriákkal, ezek további műveleteket rendelnek
az adott osztályhoz.
ComplexOperations.h
#import "Complex.h"
//kategoria - kibovito a Complex osztalyt
@interface Complex (Operations)
-(Complex*) add: (Complex*) c;
@end
ComplexOperations.m
#import "ComplexOperations.h"
@implementation Complex (Operations)
-(Complex*) add: (Complex*) c {
//allokalunk az eredmenynek egy Complex objektumot,
//es beallitjuk az adattagjait az osszegnek megfeleloen
Complex* r = [[Complex alloc] init];
[r setReal: [c real]+[self real]
andImaginary: [c imaginary]+[self imaginary]];
return r;
}
@end
ComplexMain.m
#import <stdio.h>
#import <Foundation/Foundation.h>
#import <Foundation/NSException.h>
#import <Foundation/NSAutoreleasePool.h>
#import "Complex.h"
//kategoria betoltese: kiegesziti a Complex osztalyt!
#import "ComplexOperations.h"
/*
Forditas:
gcc -o complex ComplexOperations.m ComplexMain.m Complex.m -I /GNUstep/System/Library/Headers \
-L /GNUstep/System/Library/Libraries -lobjc -lgnustep-base -fconstant-string-class=NSConstantString
*/
int main( int argc, const char *argv[] ) {
//uj objektum letrehozasa
//eloszor memoria allokalas, majd inicializalas
Complex *c = [[Complex alloc] init];
//ertekek beallitasa uzenetkuldessel uzenet: parameter formatumban
[c setReal: 1.2];
[c setImaginary: 3.4];
printf( "A komplex szam: " );
[c print];
printf( "\n" );
Complex *c2 = [[Complex alloc] init];
//tobb uzenet/parameter kuldese az objektumnak
[c2 setReal: 5.6 andImaginary: 7.8];
printf( "Egy masik komplex szam: " );
[c2 print];
printf( "\n" );
//kategoria felhasznalasa: az eredeti osztalyban meg nincs is add
//emiatt warning, de lefordul, es mukodik is
Complex *c3 = [c add: c2];
printf( "Az osszeguk: \n" );
[c3 print];
printf("\n");
//memoria felszabaditasa
[c release];
[c2 release];
[c3 release];
return 0;
}
Posing, Protokoll megvalósítás
Posing segítségével lecserléhetjük az osztály belső műveleteit, származtatás
nélkül.
posing.m
#import <Foundation/Foundation.h>
#import <Foundation/NSObject.h>
#import <stdio.h>
#import "Complex.h"
//leszarmazott osztaly, ami megvaltoztatja a print muveletet
//es megvalositja az NSCopying protokollt
@interface ComplexB: Complex <NSCopying>
-(void) print;
@end
@implementation ComplexB
//print - mas formatumban
-(void) print {
printf( "(%2.2f; %2.2f)", real, imaginary );
}
//NSCopying protokoll megvalostasahoz implementalnunk kell
//a copyWithZone muveletet
//zone definialja a felhasznalando memoriateruletet,
//ezt tovabb kell kuldenunk az allocWithZone uzenettel
-(Complex*) copyWithZone: (NSZone*) zone {
Complex* r = [[Complex allocWithZone: zone] init];
[r setReal: real];
[r setImaginary: imaginary];
return r;
}
@end
/*
Forditas:
gcc -o posing posing.m Complex.m -I /GNUstep/System/Library/Headers \
-L /GNUstep/System/Library/Libraries -lobjc -lgnustep-base -fconstant-string-class=NSConstantString
*/
int main (int argc, const char * argv[])
{
//lecseréljük a Complex osztályt, mostantól ComplexB fog létrejönni
//poseAsClass -t csak akkor szabad meghívni, amikor még
//nem küldtünk semmilyen üzenetet az osztálynak!
[ComplexB poseAsClass: [Complex class]];
Complex *c = [[Complex alloc] init];
[c setReal: 1.2 andImaginary: 3.4];
printf( "A komplex szam: " );
[c print];
printf( "\n" );
[c release];
Complex *c2 = [[Complex alloc] init];
[c2 setReal: 1.2 andImaginary: 3.4];
printf( "A komplex szam: " );
[c2 print];
printf( "\n" );
//Protokoll ellenorzes
if ( [c2 conformsToProtocol: @protocol( NSCopying )] == YES ) {
printf( "Complex conforms to NSCopying\n" );
//NSCopying hasznalat: masolhatoak az objektumok
Complex *c3 = c2;
printf( "Lemasolva: " );
[c3 print];
printf( "\n" );
}
[c2 release];
return 0;
}
Őröklődés
Az alábbiakban egy betegeket ellátó intézmény működését szemléltető példaprogramot láthatunk.
A betegek különböző betegségekkel jelentkeznek, majd a program betegségek szerint beosztja őket a megfelelő orvosokhoz, ahol azok ellátásban részesülnek.
A projekt neve: MedicalCenter
A projekt struktúrája:
MedicalCenter
|
|__lib
| |
| |__entities
| | |
| | |__Human.h, Human.m
| | |__Patient.h, Patient.m
| | |__Doctor.h, Doctor.m
| | |__Disease.h, Disease.m
| | |__Printing.h
| |
| |__utils
| |
| |__MCManager.h, MCManager.m
|
|__res
| |
| |__doctors.csv
| |__diseases.csv
| |__patients.csv
|
|_main.m
Entitások
Human.h:
#ifndef __HUMAN__
#define __HUMAN__
#include
#include
#include "Printing.h"
/**
* Emberek osztalya.
*/
@interface Human : NSObject {
NSString* id0;
int age;
NSString* gender;
NSString* name;
}
/**
* Inicializálás
*/
- (Human*) initWithParams: (NSString*) newName : (NSString*) newId : (int) newAge : (NSString*) newGender;
-(NSString*) getName;
@end
#endif
Human.m:
#include "Human.h"
@implementation Human
/**
* Inicializálás
*/
- (Human*) initWithParams: (NSString*) newName : (NSString*) newId : (int) newAge : (NSString*) newGender {
id0 = newId;
age = newAge;
gender=newGender;
name = newName;
}
- (NSString*) print {
NSString* description = @"";
description = [description stringByAppendingString: @"Name: "];
description = [description stringByAppendingString: name];
description = [description stringByAppendingString:@"; id: "];
description = [description stringByAppendingString:id0];
description = [description stringByAppendingString:@"; age: "];
description = [description stringByAppendingString:[NSString stringWithFormat:@"%d", age]];
description = [description stringByAppendingString:@"; gender: "];
description = [description stringByAppendingString:gender];
description = [description stringByAppendingString:@"; "];
return description;
}
- (NSString*) getName {
return name;
}
@end
Patient.h:
#ifndef __PATIENT__
#define __PATIENT__
#include "Human.h"
#include "Disease.h"
/**
* Betegek osztalya.
*/
@interface Patient : Human {
Disease* disease;
}
/**
* Inicializalas.
*/
- (Patient*) initPatientWithParams
: (NSString*) newName
: (NSString*) newId
: (int) newAge
: (NSString*) newGender
: (Disease*) newDisease;
- (NSString*) getDescription;
- (Disease*) getDisease;
@end
#endif
Patient.m:
#include "Patient.h"
@implementation Patient
- (Patient*) initPatientWithParams
: (NSString*) newName
: (NSString*) newId
: (int) newAge
: (NSString*) newGender
: (Disease*) newDisease {
[self initWithParams: newName : newId : newAge : newGender];
disease = newDisease;
}
- (NSString*) getDescription {
NSString* description = [self print];
description = [description stringByAppendingString: @"Disease: "];
description = [description stringByAppendingString: [disease getName]];
description = [description stringByAppendingString: @"; "];
return description;
}
- (Disease*) getDisease {
return disease;
}
@end
Doctor.h:
#ifndef __DOCTOR__
#define __DOCTOR__
#include
#include "Human.h"
#include "Disease.h"
/*
* Orvosok osztalya.
*/
@interface Doctor : Human {
NSArray* diseases;
}
/**
* Inicializalas.
*/
- (Doctor*) initDoctorWithParams
: (NSString*) newName
: (NSString*) newId
: (int) newAge
: (NSString*) newGender
: (NSArray*) newDiseases;
- (NSString*) getDescription;
- (NSArray*) getDiseases;
@end
#endif
Doctor.m:
#include "Doctor.h"
/**
* Orvosok osztalya.
*/
@implementation Doctor
/**
* Inicializalas.
*/
-(Doctor*) initDoctorWithParams
: (NSString*) newName
: (NSString*) newId
: (int) newAge
: (NSString*) newGender
: (NSArray*) newDiseases {
[self initWithParams: newName : newId: newAge : newGender];
diseases = newDiseases;
}
- (NSString*) getDescription {
NSString* description = @"";
description = [description stringByAppendingString: [self print]];
description = [description stringByAppendingString: @"Diseases: "];
description = [description stringByAppendingString: [diseases description]];
description = [description stringByAppendingString: @"; "];
return description;
}
- (NSArray*) getDiseases {
return diseases;
}
@end
Disease.h:
#ifndef __DISEASE__
#define __DISEASE__
#include
#include
#include
#include "Printing.h"
/**
* Betegsegek osztalya.
*/
@interface Disease : NSObject {
NSString* name;
NSArray* meds;
}
/**
* Inicializalas.
*/
- (Disease*) initWithParams: (NSString*) newName: (NSArray*) newMeds;
/**
* Accessor-ok.
*/
- (NSString*) getName;
- (void) setName: (NSString*) newName;
- (NSArray*) getMeds;
- (void) setMeds: (NSArray*) newMeds;
@end
#endif
Disease.m:
#include "Disease.h"
@implementation Disease
/**
* Inicializálás
*/
- (Disease*) initWithParams: (NSString*) newName : (NSArray*) newMeds {
[self setName: newName];
[self setMeds: newMeds];
}
/**
* Accessor-ok.
*/
- (NSString*) getName {
return name;
}
- (void) setName: (NSString*) newName {
name = newName;
}
- (NSArray*) getMeds {
return meds;
}
- (void) setMeds: (NSArray*) newMeds {
meds = newMeds;
}
- (NSString*) print {
NSString* description = @"";
description = [description stringByAppendingString: @"Name: "];
description = [description stringByAppendingString: name];
description = [description stringByAppendingString: @"Meds: "];
description = [description stringByAppendingString: [meds description]];
description = [description stringByAppendingString: @"; "];
return description;
}
@end
Printing.h:
#ifndef __PRINTING__
#define __PRINTING__
/**
* Objektumrol leirast szolgalgato protocol.
*/
@protocol Printing
/**
* Visszaadja az objektumrol tarolt informaciokat.
*/
-(NSString*) print;
@end
#endif
A manager osztály
MCManager.h
#ifndef __MCMANAGER__
#define __MCMANAGER__
#include
#include
#include
#include
/**
* Egeszsegkozpont manager osztaly.
*/
@interface MCManager : NSObject {
NSString* doctorResourcePath;
NSString* diseaseResourcePath;
NSString* patientResourcePath;
NSMutableArray* doctors;
NSMutableArray* diseases;
NSMutableArray* patients;
NSMutableDictionary* patientsToDoctorsMap;
NSFileManager* fm;
}
/**
* Inicializalas.
*/
- (MCManager*) initWithParams: (NSString*) newDoctorResourcePath: (NSString*) newDiseaseResourcePath : (NSString*) newPatientResourcePath;
/**
* Orvosok es kezelt betegsegek betoltese fajlbol.
*/
- (void) loadDoctors;
/**
* Betegsegek es gyogyszerek betoltese fajlbol.
*/
- (void) loadDiseases;
/**
* Betegek es betegsegek betoltese fajlbol.
*/
- (void) loadPatients;
/**
* Betegek beosztasa orvosokhoz.
*/
- (void) organizePatients;
/**
* Betegek ellatasa.
*/
- (void) treatPatients;
/**
* Orvosok listazasa.
*/
- (void) listDoctors;
/**
* Betegek listazasa.
*/
- (void) listPatients;
@end
#endif
A főprogram
main.m
#include
#include
#include
#include "lib/entities/Human.h"
#include "lib/entities/Patient.h"
#include "lib/entities/Doctor.h"
#include "lib/entities/Disease.h"
#include "lib/utils/MCManager.h"
int main(int argc, char* argv[]) {
// autorelease pool letrehozasa
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
MCManager* manager = [[MCManager alloc] init];
@try {
// manager objektum letrehozasa
[manager initWithParams: @"res/doctors.csv" : @"res/diseases.csv" : @"res/patients.csv"];
// adatok betoltese
[manager loadDoctors];
[manager loadDiseases];
[manager loadPatients];
// adatok megjelenitese
[manager listDoctors];
[manager listPatients];
// betegek beosztasa orvosokhoz
[manager organizePatients];
[manager treatPatients];
}@catch(NSException* e) {
printf("%s\n", [[e reason] cString]);
}@finally {
[pool release];
}
// memoriaterulet felszabaditasa
[pool release];
return 0;
}
A program fordítása Linux rendszeren, GCC fordítóval a következőképpen lehetséges:
gcc -o MedicalCenter -I/usr/GNUstep/System/Library/Headers main.m lib/entities/*.m
lib/utils/*.m -lobjc /usr/GNUstep/System/Library/Libraries/libgnustep-base.so -fconstant-string-class=NSConstantString -std=gnu99
Kivételkezelés
kivetel.m
#import <stdio.h>
#import <Foundation/Foundation.h>
#import <Foundation/NSException.h>
#import <Foundation/NSAutoreleasePool.h>
int main( int argc, const char *argv[] ) {
id x;
@try {
printf ("Nem letezo uzenet elkuldese: ");
[x add: x];
} @catch ( NSInvalidArgumentException *e) {
printf( "%s: ", [[e name] cString] );
} @finally {
}
return 0;
}
Szálkezelés, lockolás
thread.m
#import <Foundation/Foundation.h>
#import <unistd.h>
/*
gcc -o thread thread.m -I /GNUstep/System/Library/Headers \
-L /GNUstep/System/Library/Libraries -lobjc \
-lgnustep-base -fconstant-string-class=NSConstantString
*/
@interface NumberPrinter : NSObject
+(void) printNumbers: (id) param;
@end
//zar
NSLock *lock;
@implementation NumberPrinter
+(void) printNumbers: (id) param{
int j;
for(j=0;j<40;++j)
{
//zarolas
[lock lock];
printf("j == %i\n",j);
usleep(2000);
//zar elengedese
[lock unlock];
}
}
@end
int main(int argc, char *argv[])
{
int i;
lock = [[NSLock alloc] init];
//uj szal letrehozasa, ami futtatja a NumberPrinter osztaly printNumbers metodusat
[NSThread detachNewThreadSelector:@selector(printNumbers:) toTarget:[NumberPrinter class] withObject:nil];
for(i=0;i<40;++i)
{
[lock lock];
printf("i == %i\n",i);
printf("i ^^\n");
[lock unlock];
usleep(2000);
}
return 0;
}
Szálak - Paraméterátadás, időzítés
timer.m
#import <Foundation/Foundation.h>
#import <unistd.h>
/*
gcc -o thread thread.m -I /GNUstep/System/Library/Headers \
-L /GNUstep/System/Library/Libraries -lobjc \
-lgnustep-base -fconstant-string-class=NSConstantString
*/
@interface NumberPrinter : NSObject
//+ : statikus(osztalyszintu) metodus - nem kell objektumot letrehozni
//a hasznalathoz
+(void) printNumbers: (id) param;
@end
//zar
NSLock *lock;
@implementation NumberPrinter
+(void) printNumbers: (id) param{
int j;
for(j=0;j<40;++j)
{
//zarolas (a _lock_ nevu objektumnak kuldott uzenet: "lock")
[lock lock];
printf("j == %i\n",j);
//zar elengedese (a kuldott uzenet: "unlock")
[lock unlock];
usleep(2000);
}
}
@end
int main(int argc, char *argv[])
{
int i;
lock = [[NSLock alloc] init];
//uj szal letrehozasa, ami futtatja a NumberPrinter osztaly printNumbers metodusat
[NSThread detachNewThreadSelector:@selector(printNumbers:) toTarget:[NumberPrinter class] withObject:nil];
for(i=0;i<40;++i)
{
//blokkol, ha mar lock-olva van, megvarja a felszabaditast a
//printNumbers metodusban
[lock lock];
//a ket print egymas alatt kell, hogy megjelenjen,
//nem szakithatja meg oket "j" cimkeju sor a lock miatt
printf("i == %i\n",i);
printf("i ^^\n");
//felszabaditja a lock-ot, aki varakozik, az folytathatja tovabb a
//lockolast es feldolgozast(printNumbers)
[lock unlock];
usleep(2000);
}
return 0;
}
Taszkok
tasks.m
#import <Foundation/Foundation.h>
/*
gcc -o tasks tasks.m -I /GNUstep/System/Library/Headers \
-L /GNUstep/System/Library/Libraries -lobjc \
-lgnustep-base -fconstant-string-class=NSConstantString
*/
int main (int argc, const char * argv[])
{
//autoreleasepool szükséges ahhoz, hogy az automatikusan
//felszabadulo objektumok ténylegesen fel is szabaduljanak
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//Létrehoz egy új taszk objektumot
NSTask *task = [[NSTask alloc] init];
//Beállítja a futtatandó programot
[task setLaunchPath: @"./hello"];
//pipe a kimenet tárolásához
NSPipe *pipe = [ [ NSPipe alloc ] init ];
[task setStandardError:pipe];
[task setStandardOutput:pipe];
//pipe-ból egy file handle segítségével kiolvashatóak lesznek az adatok
NSFileHandle *file;
file = [pipe fileHandleForReading];
//futtatás
[task launch];
//megvárja, amíg befejeződik a taszk
[task waitUntilExit];
NSLog (@"Task finished!");
//kiolvassa a fájlból az adatokat
NSData *data;
data = [file readDataToEndOfFile];
//létrehoz egy sztringet a kiolvasott adatokbol
NSString *string;
string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
//kiirja az eredmenyt
NSLog (@"Result:\n%@", string);
//felszabaditja az automatikusan létrehozott objektumokat
[pool drain];
return 0;
}
RunLoop
runloop.m
#import <Foundation/Foundation.h>
#import <unistd.h>
/*
gcc verzio: i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5664)
build command: gcc -o runloop runloop.m -framework CoreFoundation -framework Foundation -l objc
*/
/*
A RunLoop obszerverenek a visszahivo metodusa
Ha tortenik valami a RunLoopban, meghivodik a
fuggveny, es a parameterbol kideritheto, hogy mi tortent
*/
void MyRunLoopObserverCallback(
CFRunLoopObserverRef observer,
CFRunLoopActivity activity,
void *info
)
{
NSString* message = nil;
switch (activity)
{
case kCFRunLoopEntry:
message = @"RunLoop entry";
break;
case kCFRunLoopBeforeTimers:
message = @"RunLoop before timers";
break;
case kCFRunLoopBeforeSources:
message = @"RunLoop before sources";
break;
case kCFRunLoopBeforeWaiting:
message = @"RunLoop before waiting";
break;
case kCFRunLoopAfterWaiting:
message = @"RunLoop after waiting";
break;
case kCFRunLoopExit:
message = @"RunLoop exit";
break;
case kCFRunLoopAllActivities:
message = @"RunLoop activities";
break;
}
NSLog(@"RunLoop observer called: %@", message);
}
/*
A szal osztaly, tartalmazza a szal main fuggvenyet, illetve
a timer altal hivott fuggvenyt, illetve egy szamlalot,
ami a timer alal hivott fuggveny lefutasait szamolja
*/
@interface MyThread : NSObject
{
int counter;
}
-(void) threadMain;
-(void) doFireTimer;
@end
@implementation MyThread
/*
A thread main fuggvenye, innen indul a masidik szal vezerlese
*/
- (void) threadMain
{
/*Szamlalo nullazasa*/
counter = 0;
/*Lekerdezzuk a szalhoz tartozo RunLoop-ot*/
NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];
/*
Letrehozunk egy RunLoopObserver objektumot (ez csak CF objektumkent
hozhato letre), es beallitjuk neki visszahivo fuggvenynek a
MyRunLoopObserverCallback fuggvenyunket
*/
CFRunLoopObserverContext context = {0, self, NULL, NULL, NULL};
CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault,
kCFRunLoopAllActivities, YES, 0, &MyRunLoopObserverCallback, &context);
/*
Hozzaadjuk az observert a RunLoophoz
*/
if (observer)
{
CFRunLoopRef cfLoop = [myRunLoop getCFRunLoop];
CFRunLoopAddObserver(cfLoop, observer, kCFRunLoopDefaultMode);
}
/*
Keszitunk egy timert, ami a doFireTimer metodusunkat fogja hivogatni
*/
[NSTimer scheduledTimerWithTimeInterval:4.5 target:self
selector:@selector(doFireTimer) userInfo:nil repeats:YES];
/*
10 iteracion keresztul fogjuk futtatni a RunLoop-unkat
*/
NSInteger loopCount = 10;
do
{
/*
A RunLoop 3 masodpercig var esemenyre, ha erkezik, futtatja
majd megszakad a kovetkezo iteracioig
*/
[myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];
loopCount--;
}
while (loopCount);
}
- (void) doFireTimer
{
NSLog(@"Timer fired %d times", ++counter);
}
@end
int main(int argc, char *argv[])
{
/*
Letrehozzuk a szal objektumot, majd elinditjuk azt
A szemetgyujtes miatt nem kell felszabaditanunk az objektumokat
*/
MyThread* myThread = [[MyThread alloc] init];
[NSThread detachNewThreadSelector:@selector(threadMain) toTarget:myThread withObject:nil];
return 0;
}
Minimalista GNUStep/AppKit desktop alkalmazás
Egy desktop alkalmazás elkészítéséhez először szükség van egy NSApplication példányra,
mely az egész alkalmazást hivatott reprezentálni. Két lehetőség van az alkalmazások
testreszabására :
- Az NSApplication specializálása (származtatása).
- Delegált osztály hozzárendelése.
A fent említett két lehetőség közüll a gyakrabban használt megoldás a delegált objektum
hozzárendelése.
A Delegált lényege hogy az NSApplication bizonyos eseményeinek kezelésére biztosítson
szabványos felületet. Bővebb információkért :
- Mac OS X Developer Library - NSApplication class reference
- Mac OS X Developer Library - NSApplicationDelegate protocol reference
A most bemutatott alkalmazásban az delegált objektumnak 3 feladata lesz :
- Az alkalmazás indulása előtt létre fogja hozni az alkalmazásban használatos GUI elemeket
- Eljárást biztosít egy egyszerű "alert" panel kijelzésére
- Mechanizmust biztosít a használt ablak láthatóvá tételére
//appdelegate.h
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
@interface AppDelegate : NSObject
{
NSApplication * owner ; // a delegált objektumhoz rendelt alkalmazás
NSWindow * main_window ; // a megjeleníteni kívánt ablak
BOOL toggle_window ; // az ablak láthatóságát vezérlő érkék
}
- (void) dealloc ; // 'clean-up' eljárás
- (void) init ; // inicializáció
- (void) printHello:(id) Sender; // az egyszerű 'alert' ablak megjelenítése
- (void) toggleWindow: (id) Sender ; // az ablak láthatóságát váltogató eljárás
- (void) setOwner:(NSApplication *)Owner ; // egyszerű beállító művelet
- (void) applicationWillFinishLaunching: (NSNotification *)not ; // NSApplicationDelegate protokol egy megvalósított eleme
@end
Az applicationWillFinishLaunching: eljárást az alkalmazás még az indulása előtt futtani fogja, ezért kitűnő alkalom
a GUI komponensek inicializációjára. Egy másik inicializációs pont lehetne például az AppDelegate objektum saját init
eljárása.
//appdelegate.m
#import <appdelegate.h>
@implementation AppDelegate : NSObject
- (void) init ;
{
// kezdetben az ablak nem látszik
toggle_window = NO ;
}
-(void) dealloc ;
{
// az ablak elengedése (csak a referenciaszámláló csökken)
[ main_window release];
// az alkalmazás elengedése (csak a referenciaszámláló csökken)
[ owner release ];
// egyéb szükséges 'clean-up' eljárások futtatása az ősosztályban
[ super dealloc ];
}
- (void) printHello:(id) Sender;
{
// 'alert' panel generálása
NSRunAlertPanel(@"Alert Panel", @"Hello world!", @"OK", @"Cancel", nil);
}
- (void) setOwner:(NSApplication *)Owner ;
{
// Az előző tulajdonos elengedése
// (az nem okoz gondot ha {owner==nil} ugyanis küldhetünk üzenetet nil-nek is!)
[owner release] ;
// A kapott objettumot beállítjuk az új értéknek
owner = Owner ;
// Fent tartunk egy referenciát az új objektumra
[Owner retain] ;
// Egyből beállítjuk az újonnan kapott alkalmazás delegáltjának saját magunkat
[owner setDelegate: self];
}
- (void) toggleWindow: (id) Sender ;
{
if( toggle_window == YES )
{
// Ha az eljárást úgy hívták meg hogy az ablak látszik akkor eltűntetjük
// (csak a képernyőről tűnik el, de nem záródik be!)
[ main_window orderOut:nil ];
toggle_window = NO ;
}
else
{
// Ha az eljárást úgy hívták meg hogy az ablak nem látszik akkor
// előre rendeljük
[ main_window makeKeyAndOrderFront:nil ];
toggle_window = YES ;
}
}
- (void) applicationWillFinishLaunching: (NSNotification *)not ;
{
// a menu elkészítése
NSMenuItem * quit_item = [NSMenuItem new];
[ quit_item setTitle: @"Quit" ];
[ quit_item setAction: @selector(terminate:) ];
[ quit_item setTarget: owner];
NSMenuItem * hello_item = [NSMenuItem new];
[ hello_item setTitle: @"Hello" ];
[ hello_item setAction: @selector(printHello:) ];
[ hello_item setTarget: self];
NSMenuItem * show_item = [NSMenuItem new];
[ show_item setTitle: @"Show window" ];
[ show_item setAction: @selector( toggleWindow: ) ];
[ show_item setTarget: self ];
NSMenu * menu = [ NSMenu new];
[menu addItem: hello_item];
[menu addItem: show_item];
[menu addItem: quit_item];
// a kész menü meállítása főmenünek
[ owner setMainMenu: menu ];
// az ablak elkészítése
NSRect rect = NSMakeRect (0, 0, 640, 480);
// A styleMask egyes biteinek állításával tujuk
// vezérelni az ablak majdani kinézetét és viselkedését.
unsigned int styleMask =
NSTitledWindowMask |
NSMiniaturizableWindowMask |
NSResizableWindowMask ; // | NSClosableWindowMask
main_window = [NSWindow alloc];
main_window = [main_window initWithContentRect: rect
styleMask: styleMask
backing: NSBackingStoreBuffered
defer: NO];
[main_window setTitle: @"This is a test window"];
// egyéb komponensek elkészítése
NSSplitView * view ;
NSButton * btn1 ;
NSButton * btn2 ;
NSTextField * label ;
btn1 = [NSButton new];
[ btn1 setTitle: @"Print Hello!"];
[ btn1 sizeToFit];
[ btn1 setTarget: self];
[ btn1 setAction: @selector (printHello:)];
btn2 = [NSButton new];
[ btn2 setTitle: @"Print Hello!2"];
[ btn2 sizeToFit];
[ btn2 setTarget: self];
[ btn2 setAction: @selector (printHello:)];
label = [NSTextField new] ;
[ label setStringValue: @"textfield : Hello!"];
[ label setEditable: YES ] ;
[ label setBordered : NO ] ;
view = [ NSSplitView new ] ;
[ view addSubview : btn1 ] ;
[ view addSubview : btn2 ] ;
[ view addSubview : label ] ;
// komponensek hozzáadása, és az ablak középre helyezése
[ main_window setContentView : view ];
[ main_window center ];
}@end
Néhány megjegyzés a fenti kódhoz :
-
A GNUStep/Cocoa környezet a koordinátasík (0,0) koordinátájának a képernyő bal alsó sarkát felelteti meg.
Szemben pl.: C#-ban szokásos bal felső sarokkal.
-
A kód Windows XP rendszeren lett tesztelve. Annak ellenére hogy a styleMask értékénél nem lett megadva az ablak
kikapcsolhatósága, meg fog jelenni a szokásos [X] azonban nem fog működni. (Helyette sípol ha megnyomják :D)
-
A kód egy nagyon egyszerű ablakot állít össze, azonban ennél jóval bonyolultabb összetételekre is van lehetőség.
Valósi fejlesztések esetében az ilyen felületek elkészítését valamilyen IDE/Tool segítségével végezzük, mint pl.:
A Mac OS X pletformon használható XCode.
-
Egy jó átfogo képet biztosít az AppKit összetételéről a következő webhely :
Mac OS X Developer Library - Applicatin Kit Framework Reference
. Amennyiben GNUStep környezetben fejlesztünk tartsuk szem előtt hogy nem minden komopnens áll rendelkezésünkre a
Cocoa eszköztárából. A GNUStep megfelelő dokumentációja megtalálható a
http://www.gnustep.org/resources/documentation/Developer/Gui/Reference/
címen, azonban nagymértékben hiányos (hiányoznak a magyarázatok nagyon sok helyen).
-
A GUI komponensek esetében gyakran találkozunk a target-action sémával. Ennek lényege hogy megadunk egy "target" objektumot
majd, egy egy paraméteres metódust (action) az objektumnak. Amikor interakció történik akkor a következő sornak megfelelő program
hajtódik végre : [target action: self];
Végezetül a program, belépési pontja :
// main.m
int main(int argc, const char** argv)
{
// NSApplication létrehozása
NSApplication * app = [NSApplication sharedApplication];
// 'app' helyett használható mindenütt az 'NSApp' konstans
// Létrehozzuk a delegált osztályt, majd beállítjuk az alkalmazást.
AppDelegate * delegate = [AppDelegate new] ;
[ delegate setOwner : app ];
return NSApplicationMain(argc , argv) ;
}
A kódot GNUMakefile segítségével fordíthatjuk :
include $(GNUSTEP_MAKEFILES)/common.make
APP_NAME = Executable
Executable_OBJC_FILES = main.m
include $(GNUSTEP_MAKEFILES)/application.make
Tologatós jaték
A továbbiakban a klasszikus tologatós játék egy lehetséges implementációja
található. A játék lényege, hogy egy kép összekevert képrészleteit megfelelően
elmozgatva, megkapjuk az eredeti képet. A felhasználónak a program indításakor
lehetősége van képet választani és meghatározni, hogy egy sor és oszlop hány darabra legyen
felosztva.
Két osztályt hozunk létre: a Tilitoli és az AppControl nevűt.
//Tilitoli.h
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
@interface Tilitoli : NSView
{
// tomb a tablamezok ertekenek tarolasara
int tabla[24][24];
// tabla merete: tdim x tdim meretu
int tdim;
// az ures mezo pozicioja
int uresX, uresY;
// azt tarolja, megvannak-e keverve a mezok
BOOL keverve;
//egy mezo merete
NSSize darabMerete;
NSImage *kep;
}
- initPont:(NSPoint)p andKep:(NSImage *)k
andDimenzio:(int)d;
- (BOOL)acceptsFirstResponder;
- (int)helyenVan;
- mozgatX:(int)x Y:(int)y;
- kever:(id)sender;
- (void)drawRect:(NSRect)r;
- (void)mouseDown:(NSEvent *)e;
@end
Most pedig az egyes metódusok implementálása:
//Tilitoli.m
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import "Tilitoli.h"
@implementation Tilitoli
// inicializalo metodus
- initPont:(NSPoint)p andKep:(NSImage *)k andDimenzio:(int)d
{
NSRect keret;
int x, y;
keret.origin = p;
keret.size = [k size];
keret.size.width -= ((int)keret.size.width)%d;
keret.size.height -= ((int)keret.size.height)%d;
[super initWithFrame:keret];
kep = k;
darabMerete.width = keret.size.width/d;
darabMerete.height = keret.size.height/d;
if (darabMerete.width<20 || darabMerete.height<20){
[NSException raise:NSInvalidArgumentException
format:@"A valasztott kep tul kicsi egy %dx%d meretu tablahoz.",
d, d];
}
tdim = d;
keverve = NO;
for(y=0; y<tdim; y++){
for(x=0; x<tdim; x++){
tabla[y][x] = y*tdim+x;
}
}
tabla[0][tdim-1] = -1;
uresX = tdim-1; uresY = 0;
return self;
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
// visszaadja, hogy hany elem van a helyen
- (int)helyenVan
{
int x, y, osszesen = 0;
for(y=0; y<tdim; y++){
for(x=0; x<tdim; x++){
if(tabla[y][x] == y*tdim+x){
osszesen++;
}
}
}
return osszesen;
}
// megadott koordinataju elemet (es a kozte es az ures hely kozt levo elemeket)
// elmozgatja a negy lehetseges irany (fel, le, jobbra, balra) kozul a
// megfelelobe
- mozgatX:(int)x Y:(int)y
{
int m;
if(x==uresX && y==uresY){
NSBeep();
}
else if(x==uresX){
if(y>uresY){ // le
for(m=uresY; m<y; m++){
tabla[m][x] = tabla[m+1][x];
}
}
else{ // fel
for(m=uresY; m>y; m--){
tabla[m][x] = tabla[m-1][x];
}
}
tabla[y][x] = -1;
uresY = y;
}
else if(y==uresY){
if(x>uresX){ // left
for(m=uresX; m<x; m++){
tabla[y][m] = tabla[y][m+1];
}
}
else{ // right
for(m=uresX; m>x; m--){
tabla[y][m] = tabla[y][m-1];
}
}
tabla[y][x] = -1; uresX = x;
}
else{
NSBeep();
}
return self;
}
// megkeveri a tablat a veletlenszeruen kivalasztott elemek es irany
// szerint. a keverest akkor tekintjuk helyesnek, ha a tablan levo elemek
// maximum negyede van jo helyen.
- kever:(id)sender
{
int maxJoHelyen = tdim*tdim/4, maxIteracio = tdim*tdim, i;
do {
for(i=0; i<maxIteracio; i++){
BOOL xTengelyMenten = lrand48()%2;
int m = lrand48()%(tdim-1);
if(xTengelyMenten==YES){
if(m>=uresX){
m++;
}
[self mozgatX:m Y:uresY];
}
else{
if(m>=uresY){
m++;
}
[self mozgatX:uresX Y:m];
}
}
} while([self helyenVan]>maxJoHelyen);
keverve = YES;
[self setNeedsDisplay:YES];
return self;
}
// kirajzolja az egesz kivalasztott kepet, vagy a megfelelo darabokat,
// attol fuggoen, hogy a tabla kevert allapotban van-e. akkor kerul meghivasra
// miutan meghivjak az NSView osztály setNeedsDisplay metódusát YES parameterrel.
- (void)drawRect:(NSRect)r
{
int x, y;
[[NSColor blackColor] set];
if(keverve==NO){
[kep compositeToPoint:r.origin
fromRect:r
operation:NSCompositeCopy];
[NSBezierPath strokeRect:[self bounds]];
return;
}
for(y=0; y<dim; y++){
for(x=0; x<tdim; x++){
int val = tabla[y][x],
px = val%tdim, py=val/tdim;
NSRect honnan, hova;
if(val==-1){
continue;
}
honnan.origin.x = px*darabMerete.width;
honnan.origin.y = py*darabMerete.height;
honnan.size = darabMerete;
hova.origin.x = x*darabMerete.width;
hova.origin.y = y*darabMerete.height;
hova.size = darabMerete;
[kep compositeToPoint:hova.origin
fromRect:honnan
operation:NSCompositeCopy];
[NSBezierPath strokeRect:hova];
}
}
}
// az eger lenyomasakor meghatarozza az eger poziciojanak megfelelo koordinatakat
// majd ez alapjan azt a darabot, amelyik felett az eger all, majd elmozgatja
// azt, ha lehet. ha az osszes darab a helyen van, akkor uzenetet ir ki
// a jatek vegerol.
- (void)mouseDown:(NSEvent *)e
{
NSPoint p;
int x, y;
p = [e locationInWindow];
p = [self convertPoint:p fromView: nil];
x = p.x/darabMerete.width; y = p.y/darabMerete.height;
if(keverve==NO || (x!=uresX && y!=uresY)){
NSBeep();
return;
}
[self mozgatX:x Y:y];
if([self helyenVan]==tdim*tdim-1){
keverve = NO;
[self display];
NSRunAlertPanel(@"Gratulalok! Nyertel!", @"Sikerult kiraknod a kepet.",
@"Ok", nil, nil);
}
else{
[self setNeedsDisplay:YES];
}
}
@end
Ezután elkészíthető az AppControl nevű osztály, melyben csak egyetlen metódust implementálunk,
méghozzá az NSApplicationDelegate protokolból. A neve applicationDidFinishLaunching.
Erre akkor lesz szükség, amikor a program belépési pontjában delegáltként beállítjuk az AppControl
osztály egy példányát. Ennek köszönhetően a delegált értesül arról, amikor az alkalmazás elindult
és még mielőtt az bármilyen eseményt fogadna lefut az applicationDidFinishLaunching metódus.
//AppControl.h
#import <Foundation/Foundation.h>
#import "Tilitoli.h"
#define MINDIM 3
#define MAXDIM 24
@interface AppControl : NSObject
- (void)applicationDidFinishLaunching:(NSNotification *)notif;
@end
//AppControl.m
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import "AppControl.h"
@implementation AppControl
// segitsegevel a delegalt tovabbi inicializacios muveleteket hajthat vegre.
// ebben az esetben itt tortenik a menu es az alkamazas alakanak letrehozasa,
// valamint a Tilitoli objektumunk létrehozása és init muveletehez tartozo
// parameterek ellenorzese.
- (void)applicationDidFinishLaunching:(NSNotification *)notif
{
NSProcessInfo *procInfo = [NSProcessInfo processInfo];
NSArray *args = [procInfo arguments];
NSString *kepUtvonal;
NSImage *kep;
int meret;
Tilitoli *tt;
NSMenu *menu = [NSMenu new];
NSWindow *ttAblak;
NSRect ablakRect;
srand48(time(NULL));
[menu addItemWithTitle: @"Keveres"
action:@selector(kever:)
keyEquivalent:@""];
[menu addItemWithTitle: @"Kilepes"
action:@selector(terminate:)
keyEquivalent:@"q"];
[NSApp setMainMenu:menu];
[menu display];
if([args count]!=3){
[NSException raise:NSInvalidArgumentException
format:@"Meg kell adni az argumentumokat: <meret> <kep>"];
}
meret = [[args objectAtIndex:1] intValue];
if(meret<MINDIM || meret>MAXDIM){
[NSException raise:NSRangeException
format:@"A meret nem csak a (%d - %d) intervallumbol lehet: %d",
MINDIM, MAXDIM, meret];
}
kepUtvonal = [args objectAtIndex:2];
kep = [[NSImage alloc] initWithContentsOfFile:kepUtvonal];
if(kep==nil){
[NSException raise:NSInvalidArgumentException
format:@"Nincs kep ezen az utvonalon: %@", kepUtvonal];
}
tt = [[Tilitoli alloc]
initPont:NSMakePoint(0, 0)
andKep:kep andDimenzio:meret];
ablakRect.origin = NSMakePoint(0, 0);
ablakRect.size = [tt bounds].size;
ttAblak = [[NSWindow alloc]
initWithContentRect:ablakRect
styleMask:NSTitledWindowMask
backing:NSBackingStoreBuffered
defer:NO];
[ttAblak setTitle:@"Tilitoli"];
[ttAblak setContentView:tt];
[ttAblak setInitialFirstResponder:tt];
[ttAblak center];
[ttAblak makeKeyAndOrderFront:nil];
}
@end
// a program belepesi pontja
int main(int argc, char** argv, char **env)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSApplication *app;
app = [NSApplication sharedApplication];
[app setDelegate:[AppControl new]];
[app run];
[pool release];
exit(0);
}
A fordításhoz a következő GNUmakefile használható:
include $(GNUSTEP_MAKEFILES)/common.make
APP_NAME = Tilitoli
Tilitoli_OBJC_FILES = Tilitoli.m AppControl.m
include $(GNUSTEP_MAKEFILES)/application.make
A fordítás után a Tilitoli.app mappába lépve a parancssorból a futtatható az alkalmazás:
./Tilitoli 4 ../virag.jpg
A fenti módon indított alkalmazás 4x4-es táblát eredményez, amin a virag.jpg kép lesz megjelenitve.
Minimalista tanulmányi rendszer
A következőekben egy egyszerű tanulmányi rendszer implementációjáról olvashatsz. Ebben a következő osztályokat implementálom:
- Student: tanuló
- Teacher: tanár
- EtrHuman: A személyek tanulmányi rendszer beli reprezentációja, a tanuló és a tanár őse.
- Course: kurzus
- ETR: Az előzőek menedzselését végzi.
A tanulók és tanárok ősosztálya két tulajdonságot, a nevet és az eha kódot tartalmazza.
//EtrHuman.h
#import
#import
//Base class for students and teachers
@interface EtrHuman : NSObject
{
//EHA code
NSString *eha_;
NSString *name_;
}
@property (readonly) NSString *name;
@property (readonly) NSString *eha;
//init function
- (id) init:(NSString *)eha_param Name:(NSString *)name_param;
@end
//EtrHuman.m
#import "EtrHuman.h"
@implementation EtrHuman
@synthesize eha=eha_;
@synthesize name=name_;
- (id) init:(NSString *)eha_param Name:(NSString *)name_param
{
if (self = [super init])
{
eha_ = eha_param;
name_ = name_param;
}
return self;
}
@end
A diák képes kurzusok felvételére, és a felvett kurzusok adatainak kiírására.
//Student.h
#import "EtrHuman.h"
#import "Course.h"
@interface Student : EtrHuman
{
//A student attends any number of courses
NSMutableArray *attend;
}
//init function
- (id) init:(NSString *)eha_param Name:(NSString *)name_param;
//add attended course
- (void) addCourse: (Course*)c;
//print attended course list to screen
- (void) printCourseList;
@end
//Student.m
#import "Student.h"
@implementation Student
- (id) init:(NSString *)eha_param Name:(NSString *)name_param;
{
if (self = [super init:eha_param Name:name_param])
{
attend = [[NSMutableArray alloc] init];
}
return self;
}
- (void) addCourse: (Course*)c
{
NSEnumerator *enumerator = [attend objectEnumerator];
Course *course;
while (course = [enumerator nextObject])
{
if ([course.code isEqualToString:c.code])
{
fprintf(stderr, "Already applied.\n");
return;
}
}
[attend addObject:c];
}
- (void) printCourseList
{
NSEnumerator *enumerator = [attend objectEnumerator];
id course;
while (course = [enumerator nextObject])
{
[course printData];
printf("\n");
}
}
@end
A tanárok és kurzusok között egy-egy kapcsolat áll fenn.
//Teacher.h
#import "EtrHuman.h"
@class Course;
@interface Teacher : EtrHuman
{
//One teacher teaches only one course ...
Course *teaches_;
}
@property (assign, readwrite) Course *teaches;
@end
//Teacher.m
#import "Teacher.h"
@implementation Teacher
@synthesize teaches=teaches_;
@end
A kurzus számontartja az őt felvevő diákokat, és a hozzárendelt tanárt.
//Course.h
#import
#import "Teacher.h"
@class Student;
@interface Course : NSObject
{
Teacher *teacher_;
NSMutableArray *students;
NSString *code_;
NSString *room_;
int day_;
int start_;
int duration_;
}
@property (assign, readwrite) Teacher *teacher;
//eg.: IPM-08sztPNYPG/x3
@property (readonly) NSString *code;
//eg.: D 1-819
@property (copy, readwrite) NSString *room;
//day of week, in [1, 7]
@property (assign, readwrite) int day;
//minutes from midnight
@property (assign, readwrite) int start;
//duration in minutes
@property (assign, readwrite) int duration;
//init function
- (id) initWithCode:(NSString *)_code;
//add attending student
- (void) addStudent:(Student *)student;
- (void) printData;
@end
//Course.m
#import "Course.h"
@implementation Course
@synthesize teacher=teacher_, code=code_, room=room_, day=day_, start=start_, duration=duration_;
- (id) initWithCode:(NSString *)_code
{
if (self = [super init])
{
code_ = _code;
students = [[NSMutableArray alloc] init];
}
return self;
}
- (void) printData
{
printf("Code: %s\n", [code_ UTF8String]);
printf("Room: %s\n", [room_ UTF8String]);
printf("Teacher: %s (%s)\n",
[teacher_.name UTF8String], [teacher_.eha UTF8String]);
printf("On the %i. day of the week\n", day_);
printf("Starts at %i:%i\n",
start_ / 60, start_ % 60);
printf("Is %i minutes long\n", duration_);
printf("Total number of students: %i\n", [students count]);
}
- (void) addStudent:(Student *)student
{
[students addObject:student];
}
@end
Az ETR végzi a diákok, tanárok és kurzusok listába gyűjtését, felületet biztosít a tantárgyak felvételére és a diákok órarendjének kiírására.
//ETR.h
#import
#import
#import "Student.h"
#import "Teacher.h"
#import "Course.h"
//class for managing courses, teachers, students
@interface ETR : NSObject
{
NSMutableArray *courses;
NSMutableArray *teachers;
NSMutableArray *students;
}
- (id) init;
//Add course, if not exists.
- (void) addCourse: (Course*)c Teacher: (Teacher*)t;
//Add student, if not exists.
- (void) addStudent: (Student*)s;
//Apply student to course, if both exist.
- (void) applyCourse: (NSString*)student_eha course: (NSString*)course_code;
//find course by code.
- (Course*) findCourse: (NSString*)course_code;
//find a student or teacher.
- (EtrHuman*) findPerson: (NSString*)eha inList:(NSMutableArray*)list;
//print timetable for all students in the list
- (void) printTimeTable;
@end
//ETR.m
#import "ETR.h"
@implementation ETR
- (id) init
{
courses = [[NSMutableArray alloc] init];
teachers = [[NSMutableArray alloc] init];
students = [[NSMutableArray alloc] init];
return self;
}
- (Course*) findCourse: (NSString*)course_code
{
NSEnumerator *enumerator = [courses objectEnumerator];
Course *course;
while (course = [enumerator nextObject])
{
if ([course.code isEqualToString:course_code])
{
return course;
}
}
return nil;
}
- (EtrHuman*) findPerson: (NSString*)eha inList:(NSMutableArray*)list
{
NSEnumerator *enumerator = [list objectEnumerator];
EtrHuman *person;
while (person = [enumerator nextObject])
{
if ([person.eha isEqualToString:eha])
{
return person;
}
}
return nil;
}
//Add course and teacher. (There is a one-one relationship between them.)
- (void) addCourse: (Course*)c Teacher: (Teacher*)t
{
Course *course = [self findCourse:c.code];
if (course != nil)
{
fprintf(stderr, "Course already exists.\n");
return;
}
Teacher *teacher = (Teacher*)[self findPerson:t.eha inList:teachers];
if (teacher != nil)
{
fprintf(stderr, "Teacher already exists.\n");
return;
}
[courses addObject:c];
[teachers addObject:t];
}
- (void) addStudent: (Student*)s
{
Student *student = (Student*)[self findPerson:s.eha inList:students];
if (student != nil)
{
fprintf(stderr, "Student already exists.\n");
return;
}
[students addObject:s];
}
- (void) applyCourse: (NSString*)student_eha course: (NSString*)course_code
{
Student *student = (Student*)[self findPerson:student_eha inList:students];
if (student == nil)
{
fprintf(stderr, "Student not found.\n");
return;
}
Course *course = [self findCourse:course_code];
if (course == nil)
{
fprintf(stderr, "Course not found.\n");
return;
}
[student addCourse:course];
[course addStudent:student];
}
- (void) printTimeTable
{
NSEnumerator *enumerator = [students objectEnumerator];
Student *student;
while (student = [enumerator nextObject])
{
printf("%s (%s) studies\n"
"--------------------\n",
[student.name UTF8String],
[student.eha UTF8String]);
[student printCourseList];
}
}
@end
Őröklődés, alakzatok, láncolt lista
A következő példaprogramban alakzatok osztályait származtatjuk egymásból. Ezek téglalap, négyzet, kör és Shape az ősosztály.
Objektumokat hozunk létre, majd ezeket szimpla láncolt listába füzzük és meghívjuk a print metódust, ami kiirja az alakzat nevét. A programban van példa dinamikuskötésre (id), methódusok (szelektorok) felüldefiniálására, illetve manuális memória kezelésre (retain, release, dealloc).
A programban látható, hogy protokol (printable) segítségével hogyan lehet kőtelezővé tenni metódusok (print) implementálását.
A program tartalmaz egy láncolt lista egy lehetséges implementációját is.
//shapes.m
//
// fordítás:
// gcc -o shapes shapes.m -I c:/GNUstep/GNUstep/System/Library/Headers -L c:/GNUstep/GNUstep/System/Library/Libraries -std=c99 -lobjc -lgnustep-base -fconstant-string-class=NSConstantString
//
#import
#import
////////////////////// egy protokoll, ami egy print selectort tartalmaz ////////////////////////
@protocol printable
@required
- (void) print;
@end
////////////////////// alakzat osztály definiciója/implementációja ////////////////////////
@interface Shape: NSObject
@end
@implementation Shape
-(void) print
{
printf( "Shape\n");
}
@end
////////////////////// alakzatok definiciója és implementációja ////////////////////////
@interface Teglalap: Shape
@end
@interface Negyzet: Teglalap
@end
@interface Kor: Shape
@end
@implementation Teglalap
-(void) print
{
printf( "Teglalap\n");
}
@end
@implementation Negyzet
-(void) print
{
printf( "Negyzet\n");
}
@end
@implementation Kor
-(void) print
{
printf( "Kor\n");
}
@end
////////////////////// a node-ok definiciója és implementációja ////////////////////////
@interface Node: NSObject {
id obj;
id next;
}
- (id) init: (id) object withNext: (id) nextnode;
- (id) obj;
- (id) next;
@end
@implementation Node
- (id) init: (id) object withNext: (id) nextnode
{
self=[super init];
//elmentjük az objektumot, majd a nextet a meglévô elemekre állítjuk
//majd mi leszünk a fejelem visszatérés után
obj=object;
next=nextnode;
return self;
}
- (id) obj
{
return obj;
}
- (id) next
{
return next;
}
- (void) dealloc
{
//ha van objektum a node-on akkor törüljük azt
if (obj!=nil)
{
[obj release];
}
//ha van next elem, akkor elöbb azt is felszabadítjuk
if (next!=nil)
{
[next release];
}
[super dealloc];
}
@end
////////////////////// a node-ok listájának definiciója és implementációja ////////////////////////
@interface List: NSObject {
id head;
}
- (id) init;
- (void) add: (id) shape;
@end
@implementation List
- (id) init
{
self=[super init];
//listánk alapban üres
head=nil;
return self;
}
- (void) add: (id) object
{
//létrehozunk egy új nodeot, ami a lánc elejére fog kerülni
// a meglévô elemeke a node nextje fog majd mutatni
head=[[Node alloc] init: object withNext: head];
}
- (void) print
{
//végig megyünk a listán, amíg az aktuális node értéke nill nem nem lesz
//az utolsó elem mindig nil lesz
for (id node=head;node!=nil;)
{
//meghívjuk az adott node objektumára a kiirást
[[node obj] print];
//majd elkérjük a következô elemet a láncban
node=[node next];
}
}
- (void) dealloc
{
//ha a fejelem nem üres, akkor törüljük
if (head!=nil)
{
[head release];
}
//meghíjuk az ôs deallocját, ha már felüldefiniáltuk azt
[super dealloc];
}
@end
////////////////////// MAIN PROGRAM ////////////////////////
int main(void)
{
//lista létrehozása
List *list=[[List alloc] init];
//alakzatok létrehozása
Teglalap *teglalap = [[Teglalap alloc] init];
Negyzet *negyzet = [[Negyzet alloc] init];
Kor *kor = [[Kor alloc] init];
Shape *shape=kor;
//hozzáadjuk az elemeket a listához
[list add:negyzet];
[list add:teglalap];
[list add:kor];
//vagy akár direkt módon is lehet hozzáadni
[list add:[[Negyzet alloc] init]];
//dinamikus teszt, itt kort adunk hozzá valójában
[shape retain]; //mert ez ugyanaz a kor amit már hozzáadtunk egyszer, hogy lehessen 2x hivni a dealloc-ot
[list add: shape];
//kiirjuk a listát
[list print];
//majd töröljuk a listát (ami majd törli az objektumokat is amiket tartalmaz)
[list release];
return 0;
}
A weblapról hiányzik a felhasználói felület, amivel az adatokat lehet rögzíteni, illetve a főprogram mivel ezek sok érdekességet már nem tartalmaznak.
A letölthető programok között ezek is megtalálhatóak.
MonkeyRunner - Alap iOS játék cocos 2D keretrendszer segítségével
A játék iOS platformra készült, nyílt forráskódú cocos 2D keretrendszer segítségével, amely a 2D világ szimulálását segíti.
cocos 2d weboldala
A játékban egy katapult segítségével kell eltalálni banánnal egy távolban lévő majmot.
MonkeyWorldLayer.h - a világot, a katapultot, töltényeket, majmot valamint a textúrákat, kameramozgást és egyéb animációkat leíró fájl header fájlja
#import "cocos2d.h"
#import "Box2D.h"
#import "GLES-Render.h"
#import "MyContactListener.h"
// HelloWorldLayer
@interface MonkeyWorldLayer : CCLayer
{
b2World* world;
GLESDebugDraw *m_debugDraw;
b2Fixture *armFixture;
b2Body *armBody;
b2RevoluteJoint *armJoint;
b2MouseJoint *mouseJoint;
b2Body *groundBody;
// ammo
NSMutableArray *bullets;
uint currentBullet;
b2Body *bulletBody;
b2WeldJoint *bulletJoint;
BOOL releasingArm;
NSMutableSet *trees;
NSMutableSet *monkeys;
// zoom logic
float oldDist, currentScale;
CGPoint oldPos;
CCLayerColor *zoombase;
CCSprite *background;
CGPoint ZB_last_posn;
// Collision
MyContactListener *contactListener;
BOOL checkCollision;
}
// returns a CCScene that contains the HelloWorldLayer as the only child
+(CCScene *) scene;
@end
MonkeyWorldLayer.mm - implementációs rész
#import "MonkeyWorldLayer.h"
//Pixel to metres ratio. Box2D uses metres as the unit for measurement.
//This ratio defines how many pixels correspond to 1 Box2D "metre"
//Box2D is optimized for objects of 1x1 metre therefore it makes sense
//to define the ratio so that your most common object type is 1x1 metre.
#define PTM_RATIO 32
#define FLOOR_HEIGHT 30.0f
#define MIN_SCALE 0.5f
#define MAX_SCALE 2.0f
// enums that will be used as tags
enum
{
kTagTileMap = 1,
kTagBatchNode = 1,
kTagAnimation1 = 1,
};
@interface MonkeyWorldLayer()
- (void)resetGame;
-(void)createBullets : (int)count;
-(BOOL)attachBullet;
-(void)createTargets;
-(void)createTarget : (NSString*)imageName atPosition : (CGPoint)position rotation : (CGFloat)rotation isCircle : (BOOL)aCircle isStatic : (BOOL)aStatic isMonkey : (BOOL)aMonkey;
-(void)zoomLayer : (float)zoomScale;
-(void)moveBoard : (CGPoint)translation from : (CGPoint)lastLocation;
@end
// MonkeyWorldLayer implementation
@implementation MonkeyWorldLayer
+ (CCScene *)scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
MonkeyWorldLayer *layer = [MonkeyWorldLayer node];
// add layer as a child to scene
[scene addChild : layer];
// return the scene
return scene;
}
// on "init" you need to initialize your instance
-(id)init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if((self = [super init]))
{
// enable touches
self.isTouchEnabled = YES;
// screen size
CGSize screenSize = [CCDirector sharedDirector].winSize;
CCLOG(@"Screen width %0.2f screen height %0.2f", screenSize.width, screenSize.height);
//[[CCTouchDispatcher sharedDispatcher] addStandardDelegate:self priority:0];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget : self action : @selector(handlePanFrom :)];
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget : self action : @selector(handlePinchFrom :)];
pan.minimumNumberOfTouches = 2;
[[[CCDirector sharedDirector] openGLView] addGestureRecognizer : pan];
[[[CCDirector sharedDirector] openGLView] addGestureRecognizer : pinch];
checkCollision = NO;
// Define the gravity vector.
b2Vec2 gravity;
gravity.Set(0.0f, -10.0f);
// Do we want to let bodies sleep?
// This will speed up the physics simulation
bool doSleep = true;
// Construct a world object, which will hold and simulate the rigid bodies.
world = new b2World(gravity, doSleep);
world->SetContinuousPhysics(true);
// Debug Draw functions
m_debugDraw = new GLESDebugDraw(PTM_RATIO);
world->SetDebugDraw(m_debugDraw);
uint32 flags = 0;
flags += b2DebugDraw::e_shapeBit;
// flags += b2DebugDraw::e_jointBit;
// flags += b2DebugDraw::e_aabbBit;
// flags += b2DebugDraw::e_pairBit;
// flags += b2DebugDraw::e_centerOfMassBit;
m_debugDraw->SetFlags(flags);
// Initialize the zoombase position
ZB_last_posn = self.position;
CCSprite *sprite = [CCSprite spriteWithFile : @"grassfront.png"];
sprite.anchorPoint = CGPointZero;
sprite.position = CGPointMake(0, FLOOR_HEIGHT - 30);
[self addChild : sprite z : 1];
sprite = [CCSprite spriteWithFile : @"grassfront.png"];
sprite.anchorPoint = CGPointZero;
sprite.position = CGPointMake(960.0f, FLOOR_HEIGHT - 30);
[self addChild : sprite z : 1];
sprite = [CCSprite spriteWithFile : @"jungle.png"];
sprite.anchorPoint = CGPointZero;
[self addChild : sprite z : -1];
sprite = [CCSprite spriteWithFile : @"jungle.png"];
sprite.anchorPoint = CGPointZero;
sprite.position = CGPointMake(960.0f, 0);
[self addChild : sprite z : -1];
sprite = [CCSprite spriteWithFile : @"monkey.png"];
sprite.anchorPoint = CGPointZero;
sprite.position = CGPointMake(180.0f, FLOOR_HEIGHT);
[self addChild : sprite z : 1];
sprite = [CCSprite spriteWithFile : @"catapult_base_2.png"];
sprite.anchorPoint = CGPointZero;
sprite.position = CGPointMake(181.0f, FLOOR_HEIGHT);
[self addChild : sprite z : 1];
sprite = [CCSprite spriteWithFile : @"catapult_base.png"];
sprite.anchorPoint = CGPointZero;
sprite.position = CGPointMake(180.0f, FLOOR_HEIGHT);
[self addChild : sprite z : 3];
// Define the ground body.
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0, 0); // bottom-left corner
// Call the body factory which allocates memory for the ground body
// from a pool and creates the ground box shape (also from a pool).
// The body is also added to the world.
groundBody = world->CreateBody(&groundBodyDef);
// Define the ground box shape.
b2PolygonShape groundBox;
// bottom
groundBox.SetAsEdge(b2Vec2(0, FLOOR_HEIGHT / PTM_RATIO), b2Vec2(screenSize.width * 4.0f / PTM_RATIO, FLOOR_HEIGHT / PTM_RATIO));
groundBody->CreateFixture(&groundBox, 0);
// top
groundBox.SetAsEdge(b2Vec2(0, screenSize.height * 4.0f / PTM_RATIO), b2Vec2(screenSize.width * 4.0f / PTM_RATIO, screenSize.height * 4.0f / PTM_RATIO));
groundBody->CreateFixture(&groundBox, 0);
// left
groundBox.SetAsEdge(b2Vec2(0, screenSize.height / PTM_RATIO), b2Vec2(0, 0));
groundBody->CreateFixture(&groundBox, 0);
// right
//groundBox.SetAsEdge(b2Vec2(screenSize.width*4.0f/PTM_RATIO,screenSize.height*2.0f/PTM_RATIO), b2Vec2(screenSize.width*4.0f/PTM_RATIO,0));
//groundBody->CreateFixture(&groundBox, 0);
// Create the catapult's arm
CCSprite *arm = [CCSprite spriteWithFile : @"catapult_arm.png"];
arm.rotation = CC_DEGREES_TO_RADIANS(-120);
[self addChild : arm z : 2];
b2BodyDef armBodyDef;
armBodyDef.type = b2_dynamicBody;
armBodyDef.linearDamping = 1;
armBodyDef.angularDamping = 1;
armBodyDef.angle = CC_DEGREES_TO_RADIANS(45);
armBodyDef.position.Set(180.0f / PTM_RATIO, (FLOOR_HEIGHT + 70.0f) / PTM_RATIO);
armBodyDef.userData = arm;
armBody = world->CreateBody(&armBodyDef);
b2PolygonShape armBox;
b2FixtureDef armBoxDef;
armBoxDef.shape = &armBox;
armBoxDef.density = 0.3F;
armBox.SetAsBox(11.0f / PTM_RATIO, 91.0f / PTM_RATIO);
armFixture = armBody->CreateFixture(&armBoxDef);
// Create a joint to fix the catapult to the floor.
//
b2RevoluteJointDef armJointDef;
armJointDef.Initialize(groundBody, armBody, b2Vec2(250.0f / PTM_RATIO, FLOOR_HEIGHT / PTM_RATIO));
armJointDef.enableMotor = true;
armJointDef.enableLimit = true;
armJointDef.motorSpeed = -200; //-1260;
armJointDef.lowerAngle = CC_DEGREES_TO_RADIANS(0);
armJointDef.upperAngle = CC_DEGREES_TO_RADIANS(40);
armJointDef.maxMotorTorque = 700; //4800;
armJoint = (b2RevoluteJoint*)world->CreateJoint(&armJointDef);
[self schedule : @selector(tick :)];
[self performSelector : @selector(resetGame) withObject : nil afterDelay : 0.5f];
// Collision
contactListener = new MyContactListener();
world->SetContactListener(contactListener);
}
return self;
}
-(void)createTargets
{
[trees release];
[monkeys release];
trees = [[NSMutableSet alloc] init];
monkeys = [[NSMutableSet alloc] init];
[self createTarget : @"monkey_.png" atPosition : CGPointMake(1405.0, FLOOR_HEIGHT) rotation : 0.0f isCircle : NO isStatic : NO isMonkey : YES];
}
-(void)createTarget : (NSString*)imageName atPosition : (CGPoint)position rotation : (CGFloat)rotation isCircle : (BOOL)aCircle isStatic : (BOOL)aStatic isMonkey : (BOOL)aMonkey
{
CCSprite *sprite = [CCSprite spriteWithFile : imageName];
[self addChild : sprite z : 1];
b2BodyDef bodyDef;
bodyDef.type = aStatic ? b2_staticBody : b2_dynamicBody;
bodyDef.position.Set((position.x + sprite.contentSize.width / 2.0f) / PTM_RATIO,
(position.y + sprite.contentSize.height / 2.0f) / PTM_RATIO);
bodyDef.angle = CC_DEGREES_TO_RADIANS(rotation);
bodyDef.userData = sprite;
b2Body *body = world->CreateBody(&bodyDef);
b2FixtureDef boxDef;
if(aMonkey)
{
boxDef.userData = (void*)1;
[monkeys addObject : [NSValue valueWithPointer : body]];
}
if(aCircle)
{
b2CircleShape circle;
circle.m_radius = sprite.contentSize.width / 2.0f / PTM_RATIO;
boxDef.shape = &circle;
}
else
{
b2PolygonShape box;
box.SetAsBox(sprite.contentSize.width / 2.0f / PTM_RATIO, sprite.contentSize.height / 2.0f / PTM_RATIO);
boxDef.shape = &box;
}
boxDef.density = 0.5f;
body->CreateFixture(&boxDef);
[trees addObject : [NSValue valueWithPointer : body]];
}
-(void)resetGame
{
// Previous bullets cleanup
if(bullets)
{
for(NSValue *bulletPointer in bullets)
{
b2Body *bullet = (b2Body*)[bulletPointer pointerValue];
CCNode *node = (CCNode*)bullet->GetUserData();
[self removeChild : node cleanup : YES];
world->DestroyBody(bullet);
}
[bullets release];
bullets = nil;
}
// Previous targets cleanup
if(trees)
{
for(NSValue *bodyValue in trees)
{
b2Body *body = (b2Body*)[bodyValue pointerValue];
CCNode *node = (CCNode*)body->GetUserData();
[self removeChild : node cleanup : YES];
world->DestroyBody(body);
}
[trees release];
[monkeys release];
trees = nil;
monkeys = nil;
}
[self createBullets : 5];
[self createTargets];
[self runAction : [CCSequence actions :
[CCMoveTo actionWithDuration : 3.0f position : CGPointMake(-1400.0f, 0.0f)],
[CCCallFuncN actionWithTarget : self selector : @selector(attachBullet)],
[CCDelayTime actionWithDuration : 0.5f],
[CCMoveTo actionWithDuration : 1.0f position : CGPointZero],
nil]];
}
-(void)createBullets : (int)count
{
currentBullet = 0;
CGFloat pos = 62.0f;
if(count > 0)
{
// delta is the spacing between bananas
// 62 is the position o the screen where we want the bananas to start appearing
// 165 is the position on the screen where we want the bananas to stop appearing
// 30 is the size of the banana
CGFloat delta = (count > 1) ? ((165.0f - 62.0f - 30.0f) / (count - 1)) : 0.0f;
bullets = [[NSMutableArray alloc] initWithCapacity : count];
for(int i = 0; i < count; i++, pos += delta)
{
// Create the bullet
//
CCSprite *sprite = [CCSprite spriteWithFile : @"banana.png"];
[self addChild : sprite z : 2];
b2BodyDef bulletBodyDef;
bulletBodyDef.type = b2_dynamicBody;
bulletBodyDef.bullet = true;
bulletBodyDef.position.Set(pos / PTM_RATIO, (FLOOR_HEIGHT + 15.0f) / PTM_RATIO);
bulletBodyDef.userData = sprite;
b2Body *bullet = world->CreateBody(&bulletBodyDef);
bullet->SetActive(false);
b2PolygonShape shape;
shape.SetAsBox(sprite.contentSize.width / 2.0f / PTM_RATIO, sprite.contentSize.height / 2.0f / PTM_RATIO);
/*b2CircleShape shape;
shape.m_radius = 15.0/PTM_RATIO;
*/
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &shape;
ballShapeDef.density = 0.8f;
ballShapeDef.restitution = 0.2f;
ballShapeDef.friction = 0.99f;
bullet->CreateFixture(&ballShapeDef);
[bullets addObject : [NSValue valueWithPointer : bullet]];
}
}
}
-(BOOL)attachBullet
{
if(currentBullet < [bullets count])
{
bulletBody = (b2Body*)[[bullets objectAtIndex : currentBullet++] pointerValue];
bulletBody->SetTransform(b2Vec2(160.0f / PTM_RATIO, (140.0f + FLOOR_HEIGHT) / PTM_RATIO), 0.0f);
bulletBody->SetActive(true);
b2WeldJointDef weldJointDef;
weldJointDef.Initialize(bulletBody, armBody, b2Vec2(160.0f / PTM_RATIO, (140.0f + FLOOR_HEIGHT) / PTM_RATIO));
weldJointDef.collideConnected = false;
bulletJoint = (b2WeldJoint*)world->CreateJoint(&weldJointDef);
return YES;
}
return NO;
}
-(void)resetBullet
{
if([monkeys count] == 0)
{
// game over
[self performSelector : @selector(resetGame) withObject : nil afterDelay : 2.0f];
}
else if([self attachBullet])
{
[self runAction : [CCMoveTo actionWithDuration : 2.0f position : CGPointZero]];
}
else
{
// We can reset the whole scene here
[self performSelector : @selector(resetGame) withObject : nil afterDelay : 2.0f];
}
checkCollision = NO;
}
-(void)ccTouchesBegan : (NSSet *)touches withEvent : (UIEvent *)event
{
if(mouseJoint != nil) return;
NSSet *set = [event allTouches];
if(set.count == 1)
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView : [myTouch view]];
location = [[CCDirector sharedDirector] convertToGL : location];
b2Vec2 locationWorld = b2Vec2(location.x / PTM_RATIO, location.y / PTM_RATIO);
if(locationWorld.x < armBody->GetWorldCenter().x + 50.0 / PTM_RATIO)
{
b2MouseJointDef md;
md.bodyA = groundBody;
md.bodyB = armBody;
md.target = locationWorld;
md.maxForce = 2000;
mouseJoint = (b2MouseJoint *)world->CreateJoint(&md);
}
}
}
-(void)ccTouchesMoved : (NSSet *)touches withEvent : (UIEvent *)event
{
if(mouseJoint == nil) return;
NSSet *set = [event allTouches];
if(set.count == 1)
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView : [myTouch view]];
location = [[CCDirector sharedDirector] convertToGL : location];
b2Vec2 locationWorld = b2Vec2(location.x / PTM_RATIO, location.y / PTM_RATIO);
mouseJoint->SetTarget(locationWorld);
}
}
-(void)handlePinchFrom : (UIPinchGestureRecognizer *)pinch
{
if(pinch.state == UIGestureRecognizerStateEnded)
{
currentScale = pinch.scale;
ZB_last_posn = self.position;
}
else if((pinch.state == UIGestureRecognizerStateBegan || (pinch.state == UIGestureRecognizerStateChanged)) && currentScale != 0.0f)
{
pinch.scale = currentScale;
}
if(pinch.scale != NAN && pinch.scale != 0.0)
{
[self zoomLayer : pinch.scale];
//pinch.view.transform = CGAffineTransformMakeScale(pinch.scale, pinch.scale);
}
}
// Zoom board
-(void)zoomLayer : (float)zoomScale
{
if((self.scale * zoomScale) <= MIN_SCALE)
{
//zoomScale = MIN_SCALE/self.scale;
return;
}
else if((self.scale * zoomScale) >= MAX_SCALE)
{
//zoomScale = MAX_SCALE/self.scale;
return;
}
self.scale = zoomScale;
//Move self so it appears to zoom from the current center of the screen.
self.position = ccp(ZB_last_posn.x * zoomScale, ZB_last_posn.y * zoomScale);
ZB_last_posn = self.position;
}
-(void)handlePanFrom : (UIPanGestureRecognizer *)recognizer
{
if(recognizer.state == UIGestureRecognizerStateBegan)
{
ZB_last_posn = self.position;
}
if(recognizer.state == UIGestureRecognizerStateChanged)
{
CGPoint translation = [recognizer translationInView : recognizer.view];
translation.y = -1 * translation.y;
[self moveBoard : translation from : ZB_last_posn];
}
}
// Pan board
-(void)moveBoard : (CGPoint)translation from : (CGPoint)lastLocation
{
CGPoint target_position = ccpAdd(translation, lastLocation);
CGSize size = [[CCDirector sharedDirector] winSize];
// Insert routine here to check that target position is not out of bounds for your background
// Remember that ZB_last_posn is a variable that holds the current position of self
if(target_position.x <= 0 && target_position.y <= 0)
self.position = target_position;
else
ZB_last_posn = lastLocation;
}
-(void)ccTouchesEnded : (NSSet *)touches withEvent : (UIEvent *)event
{
if(mouseJoint != nil)
{
if(armJoint->GetJointAngle() >= CC_DEGREES_TO_RADIANS(10))
{
releasingArm = YES;
}
world->DestroyJoint(mouseJoint);
mouseJoint = nil;
}
}
-(void)draw
{
// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
// Needed states: GL_VERTEX_ARRAY,
// Unneeded states: GL_TEXTURE_2D, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
world->DrawDebugData();
// restore default GL states
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
-(void)tick : (ccTime)dt
{
//It is recommended that a fixed time step is used with Box2D for stability
//of the simulation, however, we are using a variable time step here.
//You need to make an informed choice, the following URL is useful
//http://gafferongames.com/game-physics/fix-your-timestep/
int32 velocityIterations = 8;
int32 positionIterations = 1;
// Instruct the world to perform a single step of simulation. It is
// generally best to keep the time step and iterations fixed.
world->Step(dt, velocityIterations, positionIterations);
//Iterate over the bodies in the physics world
for(b2Body* b = world->GetBodyList(); b; b = b->GetNext())
{
if(b->GetUserData() != NULL)
{
//Synchronize the AtlasSprites position and rotation with the corresponding body
CCSprite *myActor = (CCSprite*)b->GetUserData();
myActor.position = CGPointMake(b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
// Arm is being released.
if(releasingArm && bulletJoint)
{
// Check if the arm reached the end so we can return the limits
if(armJoint->GetJointAngle() <= CC_DEGREES_TO_RADIANS(10))
{
releasingArm = NO;
// Destroy joint so the bullet will be free
world->DestroyJoint(bulletJoint);
bulletJoint = nil;
[self performSelector : @selector(resetBullet) withObject : nil afterDelay : 5.0f];
}
}
// Bullet is moving.
if(bulletBody && bulletJoint == nil)
{
b2Vec2 position = bulletBody->GetPosition();
CGPoint myPosition = self.position;
CGSize screenSize = [CCDirector sharedDirector].winSize;
// Move the camera.
if(position.x > screenSize.width / 4.0f / PTM_RATIO || position.y > screenSize.height / PTM_RATIO)
{
myPosition.x = -MIN(screenSize.width * self.scale * 4.0f - screenSize.width * self.scale, position.x * self.scale * PTM_RATIO - screenSize.width * self.scale / 4.0f);
myPosition.y = -MAX(position.y * self.scale * PTM_RATIO - screenSize.width * self.scale / 4.0f, 0);
self.position = myPosition;
}
checkCollision = YES;
}
if(checkCollision)
{
// Check for impacts
std::set::iterator pos;
for(pos = contactListener->contacts.begin();
pos != contactListener->contacts.end(); ++pos)
{
b2Body *body = *pos;
CCNode *contactNode = (CCNode*)body->GetUserData();
CGPoint position = contactNode.position;
[self removeChild : contactNode cleanup : YES];
world->DestroyBody(body);
[trees removeObject : [NSValue valueWithPointer : body]];
[monkeys removeObject : [NSValue valueWithPointer : body]];
CCParticleSun* explosion = [[CCParticleSun alloc] initWithTotalParticles : 200];
explosion.autoRemoveOnFinish = YES;
explosion.startSize = 10.0f;
explosion.speed = 70.0f;
explosion.anchorPoint = ccp(0.5f, 0.5f);
explosion.position = position;
explosion.duration = 1.0f;
[self addChild : explosion z : 11];
[explosion release];
}
}
// remove everything from the set
contactListener->contacts.clear();
}
// on "dealloc" you need to release all your retained objects
-(void)dealloc
{
// in case you have something to dealloc, do it in this method
delete world;
world = NULL;
[bullets release];
[trees release];
[monkeys release];
delete contactListener;
contactListener = NULL;
delete m_debugDraw;
// don't forget to call "super dealloc"
[super dealloc];
}
@end
MyContactListener.h - collision detection, vagyis az ütközést detektáló osztály header része
#import "Box2D.h"
#import
#import
class MyContactListener : public b2ContactListener {
public:
std::setcontacts;
MyContactListener();
~MyContactListener();
virtual void BeginContact(b2Contact* contact);
virtual void EndContact(b2Contact* contact);
virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);
virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse);
};
MyContactListener.cpp - implementációs rész
#include "MyContactListener.h"
MyContactListener::MyContactListener() : contacts()
{
}
MyContactListener::~MyContactListener()
{
}
void MyContactListener::BeginContact(b2Contact* contact)
{
}
void MyContactListener::EndContact(b2Contact* contact)
{
}
void MyContactListener::PreSolve(b2Contact* contact,
const b2Manifold* oldManifold)
{
}
void MyContactListener::PostSolve(b2Contact* contact,
const b2ContactImpulse* impulse)
{
bool isAEnemy = contact->GetFixtureA()->GetUserData() != NULL;
bool isBEnemy = contact->GetFixtureB()->GetUserData() != NULL;
if (isAEnemy || isBEnemy)
{
// Should the body break?
int32 count = contact->GetManifold()->pointCount;
float32 maxImpulse = 0.0f;
for (int32 i = 0; i < count; ++i)
{
maxImpulse = b2Max(maxImpulse, impulse->normalImpulses[i]);
}
if (maxImpulse > 1.0f)
{
// Flag the enemy(ies) for breaking.
if (isAEnemy)
contacts.insert(contact->GetFixtureA()->GetBody());
if (isBEnemy)
contacts.insert(contact->GetFixtureB()->GetBody());
}
}
}
Egyszerű böngésző a WebKit keretrendszer használatával OSX platformra.
A navbar-ban megadott címet letölti, az eseményeket naplózza és előre-hátra lép a megtekintett oldalak közt.
SBAppDelegate.h
#import
#import
@interface SBAppDelegate : NSObject {
int resourceCount;
}
@property (assign) IBOutlet NSWindow *window;
@property (assign) IBOutlet NSTextField *navbar;
@property (assign) IBOutlet WebView *webview;
@property (strong) IBOutlet NSButton *backButton;
@property (strong) IBOutlet NSButton *forwardButton;
@property (strong) IBOutlet NSProgressIndicator *progress;
- (IBAction)go:(id)sender;
@end
SBAppDelegate.mm
#import "SBAppDelegate.h"
@implementation SBAppDelegate
@synthesize backButton;
@synthesize forwardButton;
@synthesize progress;
@synthesize window;
@synthesize navbar;
@synthesize webview;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[navbar setStringValue:@"http://nyelvek.inf.elte.hu/leirasok/Objective_C/"];
[self go: navbar];
}
- (IBAction)go:(id)sender {
WebFrame *mainFrame = [webview mainFrame];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[navbar stringValue]]];
[mainFrame loadRequest: request];
}
/**
Frame Load Delegate
**/
/*!
Keretletöltés kezdete.
Most a navbar-ba beírjuk a frissen töltött címet
A bitkolbászt elindítjuk
*/
- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
NSLog(@"Keret letöltés indul: %@", [frame name]);
if(![frame parentFrame]) {
NSString *url = [[[[frame provisionalDataSource] request] URL] absoluteString];
[navbar setStringValue:url];
[progress startAnimation:frame];
}
}
/*!
Keret címe megérkezett
*/
- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame
{
NSLog(@"Keret cím megérkezett: %@ cím: %@", [frame name], title);
// Report feedback only for the main frame.
if (frame == [sender mainFrame]){
[[sender window] setTitle:title];
}
}
/*!
Keret letöltés vége
History előre-hátra engedélyezése és tiltása
A bitkolbászt leállítjuk
*/
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
{
NSLog(@"Keret letöltés kész: %@", [frame name]);
if (frame == [sender mainFrame]){
[backButton setEnabled:[sender canGoBack]];
[forwardButton setEnabled:[sender canGoForward]];
[progress stopAnimation:frame];
}
}
/*!
A szerver átirányított
*/
- (void)webView:(WebView *)sender didReceiveServerRedirectForProvisionalLoadForFrame:(WebFrame *)frame
{
NSLog(@"Szerveroldali átirányítás: %@", [frame name]);
}
/*!
Az ideiglenes letöltés sikertelem
*/
- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
{
NSLog(@"Ideiglenes letöltés sikertelen: %@ hiba: %@", [frame name], [error localizedDescription]);
}
/*!
A véglegesített letöltés sikertelem
*/
- (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
{
NSLog(@"Végleges letöltés sikertelen: %@ hiba: %@", [frame name], [error localizedDescription]);
}
/*!
Adat érkezett, letöltés véglegesíthető
*/
- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame
{
NSLog(@"Keret letöltés véglegesítve: %@", [frame name]);
}
/*!
Keret scroll pozíciója megváltozott
*/
- (void)webView:(WebView *)sender didChangeLocationWithinPageForFrame:(WebFrame *)frame
{
NSLog(@"Keret scroll pozíciója megváltozott: %@", [frame name]);
}
/*!
A keret záródik
*/
- (void)webView:(WebView *)sender willCloseFrame:(WebFrame *)frame
{
NSLog(@"A keret záródik: %@", [frame name]);
}
/**
Resource Load Delegate
**/
/*!
Új erőforrás-azonosító. Számozzuk, a következő üzenetekben a sorszámmal hivatkozunk
*/
- (id)webView:(WebView *)sender identifierForInitialRequest:(NSURLRequest *)request fromDataSource:(WebDataSource *)dataSource {
id identifier = [NSNumber numberWithInt:resourceCount++];
NSLog(@"Új erőforrás sorszám: %@, %@", [request URL], identifier);
return identifier;
}
/*!
Indul az erőforrás letöltése
*/
- (NSURLRequest *)webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource
{
NSLog(@"Erőforrás letöltése indul: %@", identifier);
return request;
}
/*!
Indul az erőforrás letöltése
*/
- (void)webView:(WebView *)sender resource:(id)identifier didReceiveResponse:(NSURLResponse *)response fromDataSource:(WebDataSource *)dataSource
{
NSLog(@"Adat jött erőforráshoz: %@", identifier);
}
/*!
Megjött az erőforrás hossza
*/
- (void)webView:(WebView *)sender resource:(id)identifier didReceiveContentLength:(int)length fromDataSource:(WebDataSource *)dataSource
{
NSLog(@"Megjött az erőforrás hossza: %@: %d", identifier, length);
}
/*!
Erőforrás kész
*/
- (void)webView:(WebView *)sender resource:(id)identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource
{
NSLog(@"Erőforrás kész: %@", identifier);
}
/*!
Erőforrás sikertelen
*/
- (void)webView:(WebView *)sender resource:(id)identifier didFailLoadingWithError:(NSError *)error fromDataSource:(WebDataSource *)dataSource
{
NSLog(@"Erőforrás sikertelen: %@, hiba: %@", identifier, [error localizedDescription]);
}
@end
Alapok a GNUStep használatával Linuxra
Két komplex szám (a,b) inicializálása, majd (a+b)*b kiszámítása
main.m
#import "MyComplexDemo.h"
#import
#import
int main( int argc, const char *argv[] )
{
NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
Writer* w = [[Writer alloc] init];
MyComplexDemo* demo = [[MyComplexDemo alloc] init];
[[w class] WriteString : @"MyComplexDemo : Initialized : Done \n"];
[demo WriteWelcome];
[[w class] WriteString : @"MyComplexDemo : WriteWelcome : Done \n"];
[demo SetupDummyComplexes];
[[w class] WriteString : @"MyComplexDemo : A Initialized : Real : \n"];
[[w class] WriteDouble : [demo GetReal_A]];
[[w class] WriteString : @"MyComplexDemo : A Initialized : Imaginary : \n"];
[[w class] WriteDouble : [demo GetImaginary_A]];
[[w class] WriteString : @"MyComplexDemo : B Initialized : Real \n"];
[[w class] WriteDouble : [demo GetReal_B]];
[[w class] WriteString : @"MyComplexDemo : B Initialized : Imaginary \n"];
[[w class] WriteDouble : [demo GetImaginary_B]];
[[w class] WriteString : @"MyComplexDemo : A + B : Real & Imaginary \n"];
[demo DemoOperationAdd];
[[w class] WriteDouble : [demo GetReal_A]];
[[w class] WriteDouble : [demo GetImaginary_A]];
[[w class] WriteString : @"MyComplexDemo : (A + B)*B : Real & Imaginary \n"];0
[demo DemoOperationMultiply];
[[w class] WriteDouble : [demo GetReal_A]];
[[w class] WriteDouble : [demo GetImaginary_A]];
[myPool drain];
return 0;
}
MyComplexDemo.h
#import
#import "MyComplex.h"
#import "Writer.h"
#import "Reader.h"
@interface MyComplexDemo : NSObject
{
MyComplex* dummyA;
MyComplex* dummyB;
Writer* demoWriter;
Reader* demoReader;
}
- (id) init;
- (void) WriteWelcome;
- (void) SetupDummyComplexes;
- (void) SetupDummy_A;
- (void) SetupDummy_B;
- (double) GetReal_A;
- (double) GetReal_B;
- (double) GetImaginary_A;
- (double) GetImaginary_B;
- (void) DemoOperationAdd;
- (void) DemoOperationMultiply;
@end
MyComplexDemo.m
#import "MyComplexDemo.h"
#import
@implementation MyComplexDemo
- (id) init
{
self = [super init];
if (!self)
{
NSLog(@"Super Class Initialization : Failed \n");
return nil;
}
else
{
dummyA = [[MyComplex alloc] init];
dummyB = [[MyComplex alloc] init];
demoWriter = [[Writer alloc] init];
demoReader = [[Reader alloc] init];
NSLog(@"Super Class Initialization : Done \n");
return self;
}
}
- (void) WriteWelcome
{
[[demoWriter class] WriteString: @"Welcome to MyComplex Demo Application \n"];
[[demoWriter class] WriteString: @"This little app will demonstrate calculating with complex numbers \n"];
}
- (void) SetupDummyComplexes
{
[self SetupDummy_A];
[self SetupDummy_B];
}
- (void) SetupDummy_A
{
double tReal, tImaginary;
[[demoWriter class] WriteString: @"Please enter complex A's Real:"];
tReal = [demoReader ReadDouble];
[[demoWriter class] WriteString: @"Please enter complex A's Imaginary:"];
tImaginary = [demoReader ReadDouble];
[dummyA SetReal : tReal];
[dummyA SetImaginary : tImaginary];
}
- (void) SetupDummy_B
{
double tReal, tImaginary;
demoReader = [[Reader alloc] init];
[[demoWriter class] WriteString: @"Please enter complex B's Real:"];
tReal = [demoReader ReadDouble];
[[demoWriter class] WriteString: @"Please enter complex B's Imaginary:"];
tImaginary = [demoReader ReadDouble];
[dummyB SetReal : tReal];
[dummyB SetImaginary : tImaginary];
}
- (double) GetReal_A
{
return [dummyA GetReal];
}
- (double) GetReal_B
{
return [dummyB GetReal];
}
- (double) GetImaginary_A
{
return [dummyA GetImaginary];
}
- (double) GetImaginary_B
{
return [dummyB GetImaginary];
}
- (void) DemoOperationAdd
{
[dummyA Add: dummyB];
}
- (void) DemoOperationMultiply
{
[dummyA Multiply: dummyB];
}
@end
MyComplex.h
#import
#import "IComparable.h"
@interface MyComplex : NSObject
{
double real;
double imaginary;
}
-(id)init;
-(void) SetReal: (double)aReal;
-(void) SetImaginary: (double)anImaginary;
-(double) GetReal;
-(double) GetImaginary;
-(MyComplex*) Add: (MyComplex*)otherComplex;
-(MyComplex*) Multiply: (MyComplex*)otherComplex;
@end
MyComplex.m
#import "MyComplex.h"
@implementation MyComplex
-(id) init
{
self = [super init];
if (!self) return nil;
else
{
return self;
}
}
- (void) SetReal : (double)aReal
{
if (aReal != 0.0)
{
real = aReal;
}
}
- (void) SetImaginary : (double)anImaginary
{
if (anImaginary != 0.0)
{
imaginary = anImaginary;
}
}
- (double) GetReal
{
return real;
}
- (double) GetImaginary
{
return imaginary;
}
- (MyComplex*) Add : (MyComplex*)otherComplex
{
if (otherComplex != 0)
{
double oReal = [otherComplex GetReal];
double oImaginary = [otherComplex GetImaginary];
real += oReal;
imaginary += oImaginary;
}
return self;
}
- (MyComplex*) Multiply: (MyComplex*)otherComplex
{
if (otherComplex != 0)
{
double oReal = [otherComplex GetReal];
double oImaginary = [otherComplex GetImaginary];
real = (oReal*real) - (oImaginary*imaginary);
imaginary = (imaginary*oReal)+(real*oImaginary);
}
return self;
}
- (BOOL) Equals: (id) otherObject
{
if (real == [otherObject GetReal] && imaginary == [otherObject GetReal])
return true;
else
return false;
}
- (BOOL) GreaterThan: (id) otherObject
{
if (real >= [otherObject GetReal] && imaginary >= [otherObject GetReal])
return true;
else
return false;
}
@end
IComparable.h
@protocol IComparable
-(BOOL)Equals:(id)otherObject;
-(BOOL)GreaterThan:(id)otherObject;
@end
Reader.h
#import
#import
@interface Reader : NSObject
{
}
-(id)init;
-(int) ReadInt;
-(double) ReadDouble;
-(float) ReadFloat;
@end
Reader.m
#import "Reader.h"
@implementation Reader
-(id) init
{
self = [super init];
if (!self) return nil;
else
{
return self;
}
}
- (int) ReadInt
{
int tempInt;
scanf(" %d ", &tempInt);
return tempInt;
}
- (double) ReadDouble
{
double tempDouble;
scanf(" %lf", &tempDouble);
return tempDouble;
}
- (float) ReadFloat
{
float tempFloat;
scanf(" %f", &tempFloat);
return tempFloat;
}
@end
Writer.h
#import
@interface Writer : NSObject
{
}
-(id)init;
+(void) WriteString : (NSConstantString*)aSource;
+(void) WriteInt : (NSConstantString*)aMessage : (int)aSource;
+(void) WriteDouble: (double)aSource;
+(void) WriteFloat : (NSConstantString*)aMessage : (float)aSource;
@end
Writer.m
#import "Writer.h"
@implementation Writer
-(id) init
{
self = [super init];
if (!self) return nil;
else
{
return self;
}
}
+ (void) WriteString : (NSConstantString*)aSource
{
NSLog(aSource);
}
+ (void) WriteInt : (NSConstantString*)aMessage : (int)aSource
{
NSLog(@"%d",aMessage, aSource);
}
+ (void) WriteDouble : (double)aSource
{
NSLog(@"%f", aSource);
}
+ (void) WriteFloat : (NSConstantString*)aMessage : (float)aSource
{
NSLog(aMessage, aSource);
}
@end
Képek letöltése párhuzamosan
A program lehetőséget biztosít képek letöltésére külön szálakban NSInvocationOperation segítségével. Megadható, hogy hány konkurens szál fusson egyszerre.
Szerző: Tóth Ã�dám (2013)
Használt fejlesztőkörnyezet: OS X 10.9, XCode 4.6.2
Példaprogram letöltése
Számológép, GNUstep alkalmazások segítségével
A fentebb bemutatott eszközök mélyebb megismeréséhez most bemutatom, hogyan lehet ezek segítségével könnyen, gyorsan grafikus felülettel
rendelkező programot készíteni Objective-C nyelven Windows alatt.
Indítsuk el a ProjectCenter-t és válasszuk a Project->New lehetőséget. A „New Projectâ€� dialógusban válaszuk az Application projekt
típusnak, és válaszuk meg a helyét és a nevét, ami jelen esetben Calculator lesz.
Ezzel létre jött a projektünk. A megjelenő fő ablakban ball felül válaszuk az Interfaces lehetőséget, aminek hatására tőle jobbra a
ProjectCenter verziójától függően több lehetőség jelenik meg. Mivel most csak a grafikus felhasználói felülettel fogunk foglalkozni a
Calculator.gorm-on kívül a többit akár el is távolítható a Project->Remove Files és a "Project and Disk" opcióval. Ezután válasszuk a
Calculator.gorm-ot aminek hatására elindul a Gorm alkalmazásunk.
Itt jegyezném meg, hogy elsőre elég zavaró lehet, hogy a GNUstep-es alkalmazások olyan módon jelennek meg, hogy külön ablakokban
van minden része, és a menüje megint csak külön életet él. Ezt a NextStep-től örökölte és kis idő után meg lehet szokni de az első
időkben eléggé oda kell figyelni.
Ha valamelyik ablak nem jelenne meg a Tools menüben tudjuk megjeleníteni őket.
A Palettes ablakban találhatóak a különböző vezérlők amiket drag&drop technikával fel is tudunk használni.
Először válaszuk a Window-t, és húzuk a Gorm Document-be
Az új elemet kiválasztva az Inspector ablakban megjelennek annak tulajdonságai, például az ablak címe, amit itt be is alíthatunk, majd
egy enter lenyomására, érvényre is jutnak. Ha azonban magának az objektumnak a nevét akarjuk bealítani, azon jobb klikkel Edit -> Set Name-el tudjuk megtenni.
Végre neki állhatunk a felhasználói felület kialakításának. A jól bevált drag&drop technikával a Palettes ablakból tegyük fel a
MainWindow-onkra a kívánt elemek, majd állítsuk be a tulajdonságaikat, és elrendezésüket nekünk tetszően.
Láthatjuk, hogy ehhez elég sok segítséget nyújt a program. Vezető vonalakkal az elrendezéshez, azonnali átméretezéssel, és a rengeteg
egyéb tulajdonság bealíthatóságával.
Valami hasonló eredmény elérése a cél:
Ezután készítsük el a vezérlő osztályunkat. A Gorm fő ablakán válasszuk a Classes részt, majd ott az NSObject osztályt és a menüben
Classes -> Create Subclass akciót. Ã�gy létrejön egy „NewClassâ€� osztály. Az új osztályt kiválasztva, az inspector ablakban szerkeszthetjük
az osztály paramétereit. Először nevezzük át CalculatorManager-nek, majd adjunk hozzá két Outlets-t, amik az osztály változói lesznek,
és 17 Actions-t, amik a metódusai lesznek. Valahogy így:
Most, hogy létrehoztuk az osztályunkat, azt kiválasztva válaszuk a Classes -> Instantiate. Erre azért van szükség, hogy jelezzük a
GNUstep-nek hozzon létre egy példányt belőle, amikor elindul az alkalmazás. Továbbá a Gorm főablakában megjelenik a CalculatorManager
objektum is.
Ezután össze kell kötni az osztály és a felület tulajdonságait. Először az outlets-eket kötjük a felületen lévő textbox-okkal,
hogy futási időben hozzáférhessünk az értékéhez a változón keresztül. Ezt úgy tehetjük meg hogy a Gorm főablakában rákattintunk a
CalculatorManager-re majd a jobb oldali Ctrl-t nyomva tartva drag&drop-oljuk a megfelelő textbox-ra. Ekkor kis magenta T jelenik meg
a textbox-ban, és zöld S jelenik meg a CalculatorManager-en. Az inspector-ban pedig kiválaszthatjuk a megfelelő Outlets-et, és ezzel
létrejön a kapcsolat.
Az akciók bekötéséhez is egész hasonlóan kell eljárnunk, csak ebben az esetben a kiválasztott gombot fogjuk meg és a jobboldali
Ctrl lenyomása mellett drag&drop-oljuk a CalculatorManager-re, ekkor a kis S és T fordítva jelenik meg, és az inspector-ban megadhatjuk,
hogy az előbb definiált action-ok közül melyik legyen a gombnoymás target-je, ezáltal létrejön a kapcsolat.
A Gorm képes automatikusan elkészíteni az így létrehozott osztály vázát, ehhez válaszuk ki a CalculatorManagert-t a class panelen,
és válaszuk a Classes -> Create Class’s Fiels. Két sikeres mentési ablak fog megjelenni a .m és a .h fájloknak. Végül az automatikusan
létrejött AppController-t törölhetjük, és így végeztünk is a Gorm használatával.
Térjünk vissza a ProjectCenter alkalmazásba, és dupla klikkeljünk a Classes-re a főablak bal felső részén, és a felugró ablakban
válaszuk a CalculatorManager.m fájlt, a header fájl automatikusan hozzáadódik a projekthez. Ezután, megjelenik a második oszlopban,
és kiválasztva már szerkeszthetjük is a kódot.
A ProjectCenter elvileg tudja buildelni, és futatni a projektet, bár nekem nem sikerült működére bírni, de ez nem gond mivel kész make
filet gyárt a projekt könyvtárába, és azt promt-ból simán tudjuk buildelni „makeâ€� paranccsal, majd indíthatjuk a projekt könyvtárban lévő
„Calculator.appâ€� mappában lévő Calculator.exe-vel.
A forráskód:
CalculatorManager.h
#include
@interface CalculatorManager : NSObject
{
id history;
id result;
double lastKnownValue;
NSString *operand;
BOOL isInEqualMod;
}
- (void) add: (id)sender;
- (void) division: (id)sender;
- (void) eight: (id)sender;
- (void) equal: (id)sender;
- (void) erase: (id)sender;
- (void) five: (id)sender;
- (void) four: (id)sender;
- (void) multiply: (id)sender;
- (void) dot: (id)sender;
- (void) nine: (id)sender;
- (void) one: (id)sender;
- (void) seven: (id)sender;
- (void) six: (id)sender;
- (void) subtract: (id)sender;
- (void) three: (id)sender;
- (void) two: (id)sender;
- (void) zero: (id)sender;
@end
CalculatorManager.m
#include
#include "CalculatorManager.h"
@implementation CalculatorManager
- (BOOL)doesStringContainDecimal:(NSString*) string
{
NSString *searchForDecimal = @".";
NSRange range = [[result stringValue] rangeOfString:searchForDecimal];
if (range.location != NSNotFound)
return YES;
return NO;
}
- (void)calculate
{
double currentValue = [result doubleValue];
if (lastKnownValue != 0)
{
if ([operand isEqualToString:@"+"])
lastKnownValue += currentValue;
else if ([operand isEqualToString:@"-"])
lastKnownValue -= currentValue;
else if ([operand isEqualToString:@"*"])
lastKnownValue *= currentValue;
else if ([operand isEqualToString:@"/"])
{
if (currentValue == 0)
[result setStringValue: @"ERR: Devide by Zero"];
else
lastKnownValue /= currentValue;
}
}
else
lastKnownValue = currentValue;
}
- (void) add: (id)sender
{
[self calculate];
operand = @"+";
[history setStringValue: [[history stringValue] stringByAppendingFormat:[result stringValue]]];
[history setStringValue: [[history stringValue] stringByAppendingFormat:@" + "]];
[result setStringValue: @""];
}
- (void) division: (id)sender
{
[self calculate];
operand = @"/";
[history setStringValue: [[history stringValue] stringByAppendingFormat:[result stringValue]]];
[history setStringValue: [[history stringValue] stringByAppendingFormat:@" / "]];
[result setStringValue: @""];
}
- (void) eight: (id)sender
{
[result setStringValue: [[result stringValue] stringByAppendingFormat:@"8"]];
}
- (void) equal: (id)sender
{
[self calculate];
[history setStringValue: [[history stringValue] stringByAppendingFormat:[result stringValue]]];
[history setStringValue: [[history stringValue] stringByAppendingFormat:@" = "]];
[result setStringValue: @""];
[result setStringValue: [NSString stringWithFormat:@"%g",lastKnownValue]];
operand = @"";
}
- (void) erase: (id)sender
{
[result setStringValue: @""];
[history setStringValue: @""];
operand = @"";
lastKnownValue = 0;
}
- (void) five: (id)sender
{
[result setStringValue: [[result stringValue] stringByAppendingFormat:@"5"]];
}
- (void) four: (id)sender
{
[result setStringValue: [[result stringValue] stringByAppendingFormat:@"4"]];
}
- (void) multiply: (id)sender
{
[self calculate];
operand = @"*";
[history setStringValue: [[history stringValue] stringByAppendingFormat:[result stringValue]]];
[history setStringValue: [[history stringValue] stringByAppendingFormat:@" * "]];
[result setStringValue: @""];
}
- (void) dot: (id)sender
{
if ([self doesStringContainDecimal:[result stringValue]] == NO && [result stringValue] != @"")
[result setStringValue: [[result stringValue] stringByAppendingFormat:@"."]];
}
- (void) nine: (id)sender
{
[result setStringValue: [[result stringValue] stringByAppendingFormat:@"9"]];
}
- (void) one: (id)sender
{
[result setStringValue: [[result stringValue] stringByAppendingFormat:@"1"]];
}
- (void) seven: (id)sender
{
[result setStringValue: [[result stringValue] stringByAppendingFormat:@"7"]];
}
- (void) six: (id)sender
{
[result setStringValue: [[result stringValue] stringByAppendingFormat:@"6"]];
}
- (void) subtract: (id)sender
{
[self calculate];
operand = @"-";
[history setStringValue: [[history stringValue] stringByAppendingFormat:[result stringValue]]];
[history setStringValue: [[history stringValue] stringByAppendingFormat:@" - "]];
[result setStringValue: @""];
}
- (void) three: (id)sender
{
[result setStringValue: [[result stringValue] stringByAppendingFormat:@"3"]];
}
- (void) two: (id)sender
{
[result setStringValue: [[result stringValue] stringByAppendingFormat:@"2"]];
}
- (void) zero: (id)sender
{
[result setStringValue: [[result stringValue] stringByAppendingFormat:@"0"]];
}
@end
Szerző: Kur Barnabás (2013)
Használt fejlesztőkörnyezet: Windows 8 Enterprise x64, GNUStep 0.30
Logikai feladvany
A feladat:
Adott 4 ember, aki át szeretne jutni a szakadék túloldalára egy hídon keresztül.
Mivel korom sötét van mindenképpen lámpát kell használniuk a hídon történő áthaladáshoz.
Lámpa csak egy van, ezért párban haladnak át a hídon és egy mindig visszahozza azt
a maradék embernek. A 4 ember különböző sebességgel képes átkelni a hídon az egyik 10, a
másik 5, a harmadik 2 és a negyedik 1 perc alatt. A kérdés, mennyi a legrövidebb idő, ami
alatt az átkelés megoldható.
A legrovidebb ut meghatarozasaban az a trukk, hogy a ket leglassabb embernek egyszerre kell
atkelnie a hidon mivel igy a masodik leglassab ideje nem szamit bele az utba. Ha atertek mar
nem is szabad mozogniuk a ket part kozott.
Ehhez sorba kell oket rendezni es a gyorsabb part atkuldeni elsonek, majd kozuluk valamelyik
visszajon (az eredmenyt nem befolyasolja a dontes, hogy melyik). Most elore kell kuldeni a
leglassabbakat es a tulpartol megint a leggyorsabb visszajon. Ekkor a ket lassu mar odaat
van es a ket gyors meg nem, mar csak nekik kell aterniuk.
Valahogy igy: {1,2} + {1} + {5,10} + {2} + {1,2}
Jeloljuk az embereknek haladasi idejuket t1,t2,t3,t4-vel melyek rendre 1,2,5,10 erteket vesznek
fel.
Ha az elobb felvazolt legolcsobb utat kepletre rendezzuk akkor ezt az eredmeny kapjuk
t_min = t1 + 3 * t2 + t4 -> 1 + 3*2 + 10 = 17
A feladathoz ket megoldast keszitettem el az egyikben (GameSpace) lepesenkent haladunk a
part kozott es mindig az adott allapottol fuggoen dontunk, hogy ki menjen at. Az egyszerubb
megoldasban (SimpleSolution) nincsenek ilyen allapotok a kapott emberek alapjan lefuttatjuk
a kepletet es kiirjuk a minimalis koltsegu kombinacionak az erteket, majd a ket part kozotti
lepeseket is kiirjuk.
Forráskód letöltése
A GameSpace is megkapja a negy embert, majd elkezdi a fent leirt logika alapjan mozgatni az
embereket, ember parokat a ket part kozott es menetkozben felirja a haladasi idot. Ha mindenki
atert a tulpartra akkor vegeztunk.
A forráskód:
GameSpace.h
#import
#import
#import
@interface GameSpace : NSObject {
NSMutableArray * peopleOnTheLeftSide;
NSMutableArray * peopleOnTheRightSide;
NSMutableArray * slowPair;
NSMutableArray * fastPair;
NSMutableArray * movingPair;
Lamp * theLamp;
int elapsedTime;
}
- (id) initGameSpace;
- (void) startWalking;
- (void) moveToSide:(Side) side;
- (void) printStatus;
- (NSMutableArray*) getFastPair;
- (NSMutableArray*) getSlowPair;
- (NSArray*) sortRightSide;
@end
GameSpace.m
#import "GameSpace.h"
@implementation GameSpace
- (id) initGameSpace
{
self = [super init];
if(self)
{
Person * p1 = [[Person alloc] initWithName:@"Anna" AndSpeed:1];
Person * p2 = [[Person alloc] initWithName:@"Bela" AndSpeed:5];
Person * p3 = [[Person alloc] initWithName:@"Nora" AndSpeed:2];
Person * p4 = [[Person alloc] initWithName:@"Dani" AndSpeed:10];
peopleOnTheLeftSide = [[NSMutableArray alloc] initWithCapacity:4];//WithObjects:p1,p2,p3,p4];
[peopleOnTheLeftSide addObject: p1];
[peopleOnTheLeftSide addObject: p2];
[peopleOnTheLeftSide addObject: p3];
[peopleOnTheLeftSide addObject: p4];
//!!!peopleOnTheLeftSide Sort;
peopleOnTheRightSide = [[NSMutableArray alloc] init];
slowPair = [ self getSlowPair];
fastPair = [ self getFastPair];
theLamp = [[Lamp alloc] init];
[theLamp setSide: Left];
elapsedTime = 0;
}
return self;
}
- (void) startWalking
{
while([peopleOnTheLeftSide count] != 0)
{
if([theLamp getSide] == Left)
[self moveToSide:Right];
else
[self moveToSide:Left];
}
}
- (void) moveToSide:(Side) side
{
if([theLamp getSide] == side) return;
switch(side)
{
case Right:
[theLamp setSide: Right];
// move the fast pair
if([peopleOnTheRightSide count] == 0)
{
[theLamp setWhoHasTheLamp:[[fastPair objectAtIndex:0] getName]];
movingPair = fastPair;
}
// slow pair is not there yet
else if([peopleOnTheRightSide count] == 1)
{
[theLamp setWhoHasTheLamp:[[slowPair objectAtIndex:0] getName]];
movingPair = slowPair;
}
// slow pair is there
else if([peopleOnTheRightSide count] == 2)
{
[theLamp setWhoHasTheLamp:[[peopleOnTheLeftSide objectAtIndex:0] getName]];
movingPair = peopleOnTheLeftSide;
}
// add moving pair
for(id p in movingPair)
{
[peopleOnTheRightSide addObject:p];
}
//[peopleOnTheRightSide addObject:[movingPair objectAtIndex:0]];
//[peopleOnTheRightSide addObject:[movingPair objectAtIndex:1]];
elapsedTime += [[movingPair objectAtIndex:1] getSpeed];
if([movingPair isEqualToArray:peopleOnTheLeftSide])
{
[peopleOnTheLeftSide removeAllObjects];
}
else
{
//for(id p in movingPair)
//{
// [peopleOnTheLeftSide removeObject:p];
//}
[peopleOnTheLeftSide removeObject:[movingPair objectAtIndex:0]];
[peopleOnTheLeftSide removeObject:[movingPair objectAtIndex:1]];
}
break;
case Left:
peopleOnTheRightSide = [NSMutableArray arrayWithArray:[self sortRightSide]];
[theLamp setWhoHasTheLamp:[[peopleOnTheRightSide objectAtIndex:0] getName]];
[theLamp setSide: Left];
elapsedTime += [[peopleOnTheRightSide objectAtIndex:0] getSpeed];
[peopleOnTheLeftSide addObject: [peopleOnTheRightSide objectAtIndex:0]];
[peopleOnTheRightSide removeObject:[peopleOnTheRightSide objectAtIndex:0]];
break;
}
[self printStatus];
}
- (NSMutableArray*) getFastPair
{
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"Speed"
ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [peopleOnTheLeftSide sortedArrayUsingDescriptors:sortDescriptors];
Person * fastPerson_1 = [sortedArray objectAtIndex:0];
Person * fastPerson_2 = [sortedArray objectAtIndex:1];
NSMutableArray * result = [[NSMutableArray alloc] initWithCapacity:2];
[result addObject:fastPerson_1];
[result addObject:fastPerson_2];
return result;
}
- (NSMutableArray*) getSlowPair
{
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"Speed"
ascending:YES] autorelease];
NSMutableArray *sortDescriptors = [NSMutableArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [peopleOnTheLeftSide sortedArrayUsingDescriptors:sortDescriptors];
Person * slowPerson_1 = [sortedArray objectAtIndex:2];
Person * slowPerson_2 = [sortedArray objectAtIndex:3];
NSMutableArray * result = [[NSMutableArray alloc] initWithCapacity:2];
[result addObject:slowPerson_1];
[result addObject:slowPerson_2];
return result;
}
- (NSArray*) sortRightSide
{
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"Speed" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
return [peopleOnTheRightSide sortedArrayUsingDescriptors:sortDescriptors];
}
- (void) printStatus
{
for (id people in peopleOnTheLeftSide)
{
NSLog([people getName]);
NSLog(@"%i",[people getSpeed]);
}
NSLog(@" /|______|\\ ");
for (id people in peopleOnTheRightSide) {
NSLog([people getName]);
NSLog(@"%i",[people getSpeed]);
}
NSLog(@"\n=================================================\n");
NSLog(@"%i", elapsedTime);
NSLog(@"\n=================================================\n");
}
@end
Lamp.h
#import
#import
@interface Lamp : NSObject {
Side side;
NSString * whoHasTheLamp;
}
-(void)setSide:(Side)s;
-(Side)getSide;
-(void) setWhoHasTheLamp:(NSString*)Name;
-(NSString*)getWhoHasTheLamp;
@end
Lamp.m
#import "Lamp.h"
@implementation Lamp
-(void)setSide:(Side)s;
{
side = s;
}
-(Side)getSide
{
return side;
}
-(void) setWhoHasTheLamp:(NSString*)Name
{
whoHasTheLamp = Name;
}
-(NSString*)getWhoHasTheLamp
{
return whoHasTheLamp;
}
@end
Person.h
@interface Person : NSObject
{
NSString *Name;
int Speed;
}
- (id) initWithName:(NSString*)name AndSpeed:(int)speed;
- (void) setName:(NSString *) name;
- (NSString*) getName;
- (void) setSpeed: (int)speed;
- (int) getSpeed;
@end
Person.m
#import "Person.h"
@implementation Person
- (id) initWithName:(NSString*)name AndSpeed:(int)speed
{
self = [super init];
if(self)
{
[self setName:name];
[self setSpeed:speed];
}
return self;
}
- (void) setName:(NSString*) name
{
Name = name;
}
- (NSString*) getName
{
return Name;
}
- (void) setSpeed:(int) speed
{
Speed = speed;
}
- (int) getSpeed
{
return Speed;
}
@end
Side.h
typedef enum {
Right = 0,
Left
} Side;
SimpleSolution.h
@interface SimpleSolution : NSObject {
NSMutableArray * people;
}
- (id) initSimpleSolution;
- (int) getMinimumTime;
- (NSArray*) sortPeople;
- (void) PrintSolution;
@end
SimpleSolution.m
#import "SimpleSolution.h"
#import "Person.h"
@implementation SimpleSolution
- (id) initSimpleSolution
{
self = [super init];
if(self)
{
Person * p4 = [[Person alloc] initWithName:@"Dani" AndSpeed:10];
Person * p1 = [[Person alloc] initWithName:@"Anna" AndSpeed:1];
Person * p3 = [[Person alloc] initWithName:@"Nora" AndSpeed:2];
Person * p2 = [[Person alloc] initWithName:@"Bela" AndSpeed:5];
people = [[NSMutableArray alloc] initWithCapacity:4];
[people addObject: p1];
[people addObject: p2];
[people addObject: p3];
[people addObject: p4];
}
return self;
}
- (int) getMinimumTime
{
NSArray * sortedArray = [self sortPeople];
return [[sortedArray objectAtIndex:0] getSpeed]
+ [[sortedArray objectAtIndex:1] getSpeed] * 3
+ [[sortedArray objectAtIndex:3] getSpeed];
}
- (NSArray*) sortPeople
{
// comment hogy hogyan lehet rendezni, beepitett lehetosegekkel.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"Speed" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
return [people sortedArrayUsingDescriptors:sortDescriptors];
}
// PRINT SCENARIO
- (void) PrintSolution
{
// beszedes kimenet.
NSLog(@"%i",[self getMinimumTime]);
}
@end
main.m
#import
#import
int main(int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
GameSpace * theGame = [[GameSpace alloc] initGameSpace];
[theGame startWalking];
SimpleSolution * sol = [[SimpleSolution alloc] initSimpleSolution];
[sol PrintSolution];
[pool release];
return 0;
}
Szerző: Gal Otto (2013)
Használt fejlesztőkörnyezet: Xcode 4.6.2
Egyszerű számológép storyboard segítségével
>>> SimpleCalculator progam innent letölthető <<<
Hozzunk létre egy új projektet és ügyeljünk arra, hogy a storyboard is be legyen pipálva.
A fejlesztői környezetből nyissuk meg a Main.storyboard fájlt. A storyboard-ba huzzuk bele a gombokat a jobb alsó sarokból a drag-n-drop módszert alkalmazva. Formázzuk is meg, nevezzük át, stb. Amikor ezzel elkészültnk, osszuk meg a képernyőt, amit úgy tudunk megtenni, hogy a jobb felső sarok középső ikonját választjuk ki (a csokornyakkendőset), majd jelöljük ki egy objektumot. Ekkor a ctrl+bal egér gombot tartsuk lenyomva és húzzuk bele a ViewController.h fájlba, majd eresszük el és rendeljünk hozzá eseményeket, hasonlóan mint a lenti képen (ügyeljünk arra, hogy ha gombokhoz akciót szeretnénk rendelni, akkor az Connection Outlet helyett az IBAction-t válasszuk, a label-ekhez outlet-et használunk). Ha ezzel megvagyunk, hasonlóan kell kinéznie a fáljnak, mint a ViewController.h. A többi részt fejtsük ki a ViewController.m fájlban hasonlóan, mint ami lejjebb megtalálható.
A továbbfejlestzéshez csak a fantáziánk szabhat határt.
ViewController.h
#import
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *consoleLabel;
@property (weak, nonatomic) IBOutlet UILabel *operatorLabel;
- (IBAction)one:(id)sender;
- (IBAction)two:(id)sender;
- (IBAction)three:(id)sender;
- (IBAction)four:(id)sender;
- (IBAction)five:(id)sender;
- (IBAction)six:(id)sender;
- (IBAction)seven:(id)sender;
- (IBAction)eight:(id)sender;
- (IBAction)nine:(id)sender;
- (IBAction)zero:(id)sender;
- (IBAction)dot:(id)sender;
- (IBAction)clear:(id)sender;
- (IBAction)divide:(id)sender;
- (IBAction)multiple:(id)sender;
- (IBAction)minus:(id)sender;
- (IBAction)plus:(id)sender;
- (IBAction)sqrt:(id)sender;
- (IBAction)suqare:(id)sender;
- (IBAction)total:(id)sender;
@end
ViewController.m
#import "ViewController.h"
// műveletek deklarálása
typedef enum {
Plus,
Minus,
Multiply,
Divide,
Sqrt,
Square,
Equal
} Operation;
// változók deklarálása
@interface ViewController ()
{
double result;
NSString *store, *log;
int operator;
BOOL isCalculated;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self initialize];
}
// inicializáló függvény
- (void)initialize {
result = 0;
store = @"";
log = @"";
isCalculated = NO;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// az 1-es gomb lenyomása hatására történő esemény
- (IBAction)one:(id)sender {
[self addNumberToTheConsole:1];
}
// a 2-es gomb lenyomása hatására történő esemény
- (IBAction)two:(id)sender {
[self addNumberToTheConsole:2];
}
// a 3-as gomb lenyomása hatására történő esemény
- (IBAction)three:(id)sender {
[self addNumberToTheConsole:3];
}
// a 4-es gomb lenyomása hatására történő esemény
- (IBAction)four:(id)sender {
[self addNumberToTheConsole:4];
}
// a 5-ös gomb lenyomása hatására történő esemény
- (IBAction)five:(id)sender {
[self addNumberToTheConsole:5];
}
// a 6-os gomb lenyomása hatására történő esemény
- (IBAction)six:(id)sender {
[self addNumberToTheConsole:6];
}
// a 7-es gomb lenyomása hatására történő esemény
- (IBAction)seven:(id)sender {
[self addNumberToTheConsole:7];
}
// a 8-as gomb lenyomása hatására történő esemény
- (IBAction)eight:(id)sender {
[self addNumberToTheConsole:8];
}
// a 9-es gomb lenyomása hatására történő esemény
- (IBAction)nine:(id)sender {
[self addNumberToTheConsole:9];
}
// a 0 gomb lenyomása hatására történő esemény
- (IBAction)zero:(id)sender {
[self addNumberToTheConsole:0];
}
// a , gomb lenyomása hatására történő esemény
- (IBAction)dot:(id)sender {
store = [store stringByAppendingString:@"."];
log = [log stringByAppendingString:@"."];
[self.consoleLabel setText:store];
[self.operatorLabel setText:log];
}
// a c gomb lenyomása hatására történő esemény
- (IBAction)clear:(id)sender {
store = @"";
log = @"";
result = 0.0;
isCalculated = YES;
[self.consoleLabel setText:@"0"];
[self.operatorLabel setText:log];
}
// a minusz művelet lenyomása hatására történő esemény
- (IBAction)minus:(id)sender {
[self logic:Minus];
}
// a plusz művelet lenyomása hatására történő esemény
- (IBAction)plus:(id)sender {
[self logic:Plus];
}
// a szorzás művelet lenyomása hatására történő esemény
- (IBAction)multiple:(id)sender {
[self logic:Multiply];
}
// az osztás művelet lenyomása hatására történő esemény
- (IBAction)divide:(id)sender {
[self logic:Divide];
}
// a gyökvonás művelet lenyomása hatására történő esemény
- (IBAction)sqrt:(id)sender {
[self logic:Sqrt];
}
// a négyzetreemelés művelet lenyomása hatására történő esemény
- (IBAction)suqare:(id)sender {
[self logic:Square];
}
// az egyenlőség művelet lenyomása hatására történő esemény
- (IBAction)total:(id)sender {
[self logic:Equal];
}
// a logikákat leíró függvény
- (void)logic:(int)type {
double tmpNum = [store doubleValue];
double res = 0.0;
// plusz gomb hatására vonatkozó esemény
if (type == Plus) {
operator = Plus;
result = [store doubleValue];
store = @"";
[self.consoleLabel setText:store];
log = [log stringByAppendingString:@" + "];
[self.operatorLabel setText:log];
}
// minusz gomb hatására vonatkozó esemény
if (type == Minus) {
operator = Minus;
result = [store doubleValue];
store = @"";
[self.consoleLabel setText:store];
log = [log stringByAppendingString:@" - "];
[self.operatorLabel setText:log];
}
// szorzás gomb hatására vonatkozó esemény
if (type == Multiply) {
operator = Multiply;
result = [store doubleValue];
store = @"";
[self.consoleLabel setText:store];
log = [log stringByAppendingString:@" * "];
[self.operatorLabel setText:log];
}
// osztás gomb hatására vonatkozó esemény
if (type == Divide) {
operator = Divide;
result = [store doubleValue];
store = @"";
[self.consoleLabel setText:store];
log = [log stringByAppendingString:@" / "];
[self.operatorLabel setText:log];
}
// gyökvonás gomb hatására vonatkozó esemény
if (type == Sqrt) {
operator = Sqrt;
log = [NSString stringWithFormat:@"sqrt(%f)", tmpNum];
res = sqrt(tmpNum);
store = [NSString stringWithFormat:@"%f", res];
[self.consoleLabel setText:store];
[self.operatorLabel setText:log];
store = @"";
isCalculated = YES;
}
// négyzetre emelés gomb hatására vonatkozó esemény
if (type == Square) {
operator = Square;
log = [NSString stringWithFormat:@"pow(%f, 2)", tmpNum];
res = pow(tmpNum, 2);
store = [NSString stringWithFormat:@"%f", res];
[self.consoleLabel setText:store];
[self.operatorLabel setText:log];
store = @"";
isCalculated = YES;
}
// egyenlőség gomb hatására vonatkozó esemény
if (type == Equal) {
log = @"";
[self.operatorLabel setText:log];
switch (operator) {
case Plus:
res = result + tmpNum;
break;
case Minus:
res = result - tmpNum;
break;
case Multiply:
res = result * tmpNum;
break;
case Divide:
res = result / tmpNum;
break;
default:
break;
}
[self.consoleLabel setText:[NSString stringWithFormat:@"%f", res]];
isCalculated = YES;
}
}
// a console-ra való kiíratás
-(void)addNumberToTheConsole:(int)number{
if (isCalculated) {
log = @"";
store = @"";
isCalculated = !isCalculated;
result = 0;
}
store = [store stringByAppendingString:[NSString stringWithFormat:@"%d", number]];
log = [log stringByAppendingString:[NSString stringWithFormat:@"%d", number]];
[self.consoleLabel setText:store];
[self.operatorLabel setText:log];
}
@end
Szerző: Zsivics Sanel (2014)
Használt fejlesztőkörnyezet: Xcode 5.1
XML Parser használata + lokális értesítések létrehozása iOS rendszeren
>>> A program innen letölthető <<<
XMLParser
// Kezdo tagek beolvasasa. Ha akkor inicializalom a books tombot, egyebkent ha akkor letrehozok egy uj Book objektumot
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:@"Books"]) {
// tomb inicializalasa
appDelegate.books = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:@"book"]) {
//Book objektum inicializalasa
aBook = [[Book alloc] init];
//Book ID beallitasa az attributumbol
aBook.bookID = [[attributeDict objectForKey:@"id"] integerValue];
NSLog(@"id beolvasasa :%i", aBook.bookID);
}
NSLog(@"Elem feldolgozasa: %@", elementName);
}
// egy XML elem ertekenk olvasasa karakterenkent
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
// ha ures az aktualis elem, akkor letrehozom
if(!currentElementValue)
currentElementValue = [[NSMutableString alloc] initWithString:string];
else // egyebkent hozzaadom a karaktert
[currentElementValue appendString:string];
NSLog(@"Ertek feldolgozasa: %@", currentElementValue);
}
// zaro tag feldolgozasa, itt kapja meg a vegleges erteket a Book objektum megfelelo tagja
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
// nem kell csinalni semmit
if([elementName isEqualToString:@"Books"])
return;
// elemnel hozzaadom a Book elemet a books tombhoz es felszabaditom
if([elementName isEqualToString:@"book"]) {
[appDelegate.books addObject:aBook];
[aBook release];
aBook = nil;
}
else
[aBook setValue:currentElementValue forKey:elementName];
[currentElementValue release];
currentElementValue = nil;
}
Értesítések létrehozása kölcsönzési idő lejárat előtti figyelmeztetéshez:
// letrehozza az ertesiteseket a kolcsonzesi ido lejaratarol, es ertesit rogton a lejart kolcsonzesi hataridokrol.
- (void) setExpires {
[[UIApplication sharedApplication] cancelAllLocalNotifications];
// vegig megy a beolvasott konyveken
for (Book* book in books) {
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
// date formatter letrehozasa a string -> date konverziohoz, ha a DateFormatter string nem egyezik az XML-ben
// levo date string formatumaval akkor nil objektumot kapunk!
[dateFormatter setDateFormat:@"yyyy.MM.dd"];
//[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"Europe/Budapest"]];
NSDate *dateFromString = [[NSDate alloc] init];
// \n\r karakterek torlese a datum stringbol
book.expiration = [book.expiration stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
// datumma konvertalas
dateFromString = [dateFormatter dateFromString:book.expiration];
// konverzios hiba volt?
if (dateFromString == nil)
{
[self showMsg:[NSString stringWithFormat:@"Hiba tortent a %@ datum konvertalasakor.", book.expiration]];
continue;
}
localNotification.timeZone = [NSTimeZone timeZoneWithName:@"Europe/Budapest"];
// lejart a kolcsonzesi ido?
if ([self isExpired:dateFromString])
{
// ertesitem a felhasznalot
[self showMsg:[NSString stringWithFormat:@"A %@ könyv %@-n már lejárt!", book.title, book.expiration]];
}
else { // kesobb fog lejarni, letrehozom a lejarati ido - 1 nap-ra az ertesitest
dateFromString = [dateFromString dateByAddingTimeInterval:-1*24*60*60];
localNotification.fireDate = dateFromString;
localNotification.alertBody = [NSString stringWithFormat:@"A %s könyv holnap lejár!", book.title];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
[localNotification release];
}
[dateFormatter release];
}
// letrehozott ertesitesek kiloggolasa
[self logNotifications];
}
Szerző: Fahmi Arman (2014)
Használt fejlesztői környezet: Xcode 4.2
Bináris keresőfa
>>> A program innen letölthető <<<
A példaprogram egy bináris keresőfa, amely tetszőleges, összehasonlítható értékű elemek tárolására alkalmas. Rendelkezik beszúrás és törlés műveletekkel, valamint egy inorder
bejárás művelettel is. Az inorder bejárás egyben ki is írja az egyes csúcsok értékeit, így rendezett sorozatot kapunk.
A program két fő fájlból áll: Node.m és Node.h. Ezen kívül létrehoztam egy main.m fájlt, ami a bináris keresőfa használatát mutatja be.
Node.h
// A C-s include helyett importot használunk
#import
//Node osztály specifikációja
@interface Node : NSObject // minden osztály alapértelmezett ősosztálya az NSObject
{
//adattagok, alapértelmezetten protected elérésűek
Node *left; // bal gyerek
Node *right; // jobb gyerek
NSObject *data; // a csúcsban tárolt adat
}
// metódusok deklarációja, amelyeket az implementációban (.m fájl) valósítunk meg
// a metódusok neve magába foglalja a paraméterek nevét is
// - jel jelöli a példánymetódusokat, + az osztálymetódusokat
// a függvénynek két paramétere van: egy Node* és egy NSObject*, visszatérési értéke Node*
-(Node*) insertNode:(Node*) root Object:(NSObject*)data;
// a függvénynek két paramétere van: egy Node* és egy NSObject*, visszatérési értéke Node*
-(Node*) deleteNode:(Node*) root Value:(NSObject*) value;
//a függvénynek egy paramétere van: Node* és void visszatérési értékű
-(void) inorderTraversal:(Node*) root;
// a property kulcsszóval ellátott adattagokhoz automatikusan
// getter és setter művelet generálódik, ha az implementációban
// synthesize kulcsszóval látjuk el
@property (nonatomic, assign) Node *left; // assign jelentése, hogy cím szerinti értékadást szeretnénk biztosítani az adattagnak
@property (nonatomic, assign) Node *right;
@property (nonatomic, assign) NSObject *data;
@end // end kulcsszó jelöli a specifikáció végét
Node.m
// A C-s include helyett importot használunk
#import "Node.h"
@implementation Node // osztály megvalósítását az implementation kulcsszó vezeti be
@synthesize left; // a synthesize kulcsszóval ellátott adattagokhoz automatikus getter és setter művelet generálódik
@synthesize right;
@synthesize data;
// beszúrás művelet, amely a közismert bináris keresőfa beszúrás algoritmusnak megfelelően működik
-(Node*) insertNode:(Node*) root Object:(NSObject*)data
{
Node *current = root;
Node *previous = nil;
Node *temp = [[Node alloc] init]; // temp objektum inicializálása az init művelettel, memóriafoglalás pedig az alloc művelettel
temp.data = data;
temp.left = temp.right = nil; //lehetőség van többszörös értékadásra
if(root == nil) //ha a fa üres, akkor beszúrjuk az első elemet
{
root = temp;
}
else // ha a fa nem üres
{
// végigjárjuk a csúcsokat, megkeressük az új érték helyét
while (current != nil)
{
previous = current;
NSString *strValue2 = (NSString*) current.data;
// ha a beszúrandó érték kisebb, mint az aktuálisan vizsgált elem, akkor balra, egyébként jobbra lépünk a fában
current = ([data compare:current.data options:(NSCaseInsensitiveSearch | NSAnchoredSearch)] == NSOrderedAscending) ? current.left :current.right;
}
if ([data compare:previous.data options:(NSCaseInsensitiveSearch | NSAnchoredSearch)] == NSOrderedAscending)
{
previous.left = temp;
}
else
{
previous.right = temp;
}
}
return root;
}
// érték törlése a fából, amely a közismert bináris keresőfa törlés algoritmusnak megfelelően működik
-(Node*) deleteNode:(Node*) root Value:(NSObject*) value
{
if (root == nil) // ha a fa üres
{
return root;
}
Node *current = root;
Node *parent; //a törléshez meghatározzuk és számontartjuk az keresendő érték szülő csúcsát
while (current != nil && [value compare:current.data options:(NSCaseInsensitiveSearch | NSAnchoredSearch)] != NSOrderedSame )
{
parent = current;
// ha a törlendő érték kisebb, mint az aktuálisan vizsgált elem, akkor balra, egyébként jobbra lépünk a fában
current = [value compare:current.data options:(NSCaseInsensitiveSearch | NSAnchoredSearch)] == NSOrderedAscending ? current.left : current.right;
}
if (current == nil) // ha nem találtuk meg az értéket a fában
{
return root;
}
Node *helper;
Node *suc;
if (current.left == nil) //ha a törlendő csúcs bal részfája üres
{
helper = current.right;
}
else if (current.right == nil) //ha a törlendő csúcs jobb részfája üres
{
helper = current.left;
}
else //ha a törlendő csúcs egyik részfája sem üres
{
suc = current.right;
while (suc.left != nil)
{
suc = suc.left;
}
suc.left = current.left;
helper = current.right;
}
if (parent == nil)
{
return helper;
}
if (current == parent.left)
{
parent.left = helper;
}
else
{
parent.right = helper;
}
current = nil;
return root;
}
// fa bejárása rekurzívan, inorder módon, így rendezett sorozatot kapunk
-(void) inorderTraversal:(Node*)root
{
if(root != nil)
{
// self objektum az aktuális osztálypéldányt tartlmazza, arra hívjuk meg rekurzívan az inorderTraversal műveletet
[self inorderTraversal:root.left];
// NSLog függvény a konzolra írja a megadott adatot, hasonló a használata, mint a printf függvénynak C- ben
NSLog(@"%@ ", root.data);
[self inorderTraversal:root.right];
}
}
@end // az osztály megvalósítását az end kulcsszóval zárjuk
main.m
// A C-s include helyett importot használunk
#import "Node.m"
//main függvény
int main(void)
{
Node *binarySearchTreeString = [[Node alloc] init]; // memóriafoglalás a Node osztály számára, majd példányosítása
Node *rootString = nil; // a C-ből ismert NULL helyett itt nil-t használunk
// tömb inicializálása karakterekkel, memóriafoglalás az alloc művelettel
NSArray *arrayString = [[NSArray alloc] initWithObjects:@"b",@"d",@"c",@"f",@"h",@"x",@"y", nil]; // értékek megadásakor az utolsó elem kötelezően a nil
for (NSObject *val in arrayString) //a C#- ból ismert foreach ciklus megfelelője
{
// a Smalltalk üzenetküldésének mintájára történő metódushívás root és val paraméterekkel
// egyenként hozzáadjuk az array elemeit a fához
rootString=[binarySearchTreeString insertNode:rootString Object:val];
}
// törlés függvény hívása root és "x" paraméterekkel
// a @ jel jelöli az Objective-C objektumokat
[binarySearchTreeString deleteNode:rootString Value:@"x"];
[binarySearchTreeString deleteNode:rootString Value:@"d"];
// fa inorder bejárása, amely a rendezett sorozat képernyőre írását eredményezi
[binarySearchTreeString inorderTraversal:rootString];
Node *binarySearchTreeInt = [[Node alloc] init]; // memóriafoglalás a Node osztály számára, majd példányosítása
Node *rootInt = nil; // a C-ből ismert NULL helyett itt nil-t használunk
// tömb inicializálása egész értékekkel, memóriafoglalás az alloc művelettel
NSArray *arrayInt = [[NSArray alloc] initWithObjects:@"13",@"49",@"51",@"19",@"87",@"33",@"75", nil]; // értékek megadásakor az utolsó elem kötelezően a nil
for (NSObject *val in arrayInt) //a C#- ból ismert foreach ciklus megfelelője
{
// a Smalltalk üzenetküldésének mintájára történő metódushívás root és val paraméterekkel
// egyenként hozzáadjuk az array elemeit a fához
rootInt=[binarySearchTreeInt insertNode:rootInt Object:val];
}
// törlés függvény hívása root és "75" paraméterekkel
// a @ jel jelöli az Objective-C objektumokat
[binarySearchTreeInt deleteNode:rootInt Value:@"75"];
[binarySearchTreeInt deleteNode:rootInt Value:@"19"];
// fa inorder bejárása, amely a rendezett sorozat képernyőre írását eredményezi
[binarySearchTreeInt inorderTraversal:rootInt];
return 0;
}
Szerző: Bereczki Gréta Tamara (2014)
Használt fordító: GNUStep Windows Developer 1.4.0
Reflekciós műveletek
>>> A program innen letölthető <<<
A példaprogram futási időben létrehoz egy (ős)osztályt, amelynek van egy darab művelete. Majd létrehozunk egy (gyermek)osztályt (szintén futási időben), amely megöröki ezt a műveletet,
majd ebben felüldefiniáljuk az ősosztály műveletét. A példa bemutatja ezen reflekciós eszközök használatát, valamint azt, hogy például el tudjuk érni, hogy a gyermek osztályból
a szülő osztály eredeti műveletét hívjuk meg. Lekérdezzük a metódusokat, kiváltsunk metódust, típusellenőrzést végezzünk.
main.m
#import "objc/runtime.h"
#import
static id instanceOfRuntimeSuperClass;
static id instanceOfRuntimeSubClass;
static Class runtimeSuperClass;
static Class runtimeSubClass;
//skeleton of the dummy main method
static NSString *MainMethod(id self, SEL _cmd)
{
NSString* className = NSStringFromClass([self class]);
return [NSString stringWithFormat: @"This is a MAIN METHOD, from 'MainMethod' method from: %@", className];
}
//skeleton of the the dummy sub method
static NSString *SubMethod(id self, SEL _cmd)
{
NSString* className = NSStringFromClass([self class]);
return [NSString stringWithFormat: @"This is a SUB METHOD, from 'SubMethod' method from: %@", className];
}
//add the given method to the SuperClass by "easy" encoding, (without handwritten signature string)
void addMethodToSuperClassByEasyEncoding()
{
//add the type by getting the info from another class
Method description = class_getInstanceMethod([NSObject class], @selector(description));
const char *types = method_getTypeEncoding(description);
//now add the method (with signature and implementation)
class_addMethod(runtimeSuperClass, @selector(description), (IMP)MainMethod, types);
}
//create a superclass and its instance
void createARuntimeSuperClass()
{
//Create a superclass
runtimeSuperClass = objc_allocateClassPair([NSObject class], "RuntimeSuperClass", 0);
//Get classname of runtime class
NSString* className = NSStringFromClass([runtimeSuperClass class]);
addMethodToSuperClassByEasyEncoding();
//register the class
objc_registerClassPair(runtimeSuperClass);
//create an instance of the RuntimeClass
instanceOfRuntimeSuperClass = [[runtimeSuperClass alloc] init];
NSLog(@"Instance of the SuperClass has been created...");
}
void overrideMethodInSubClassByHardEncoding(void)
{
//add the type by getting the info from another class
Method description = class_getInstanceMethod([NSObject class], @selector(description));
//create the signature string for the method
NSString *typesNS = [NSString stringWithFormat: @"%s%s%s%s",
@encode(NSUInteger),
@encode(id), @encode(SEL),
@encode(id)];
const char *types = [typesNS UTF8String];
//'override' the 'description' method with the other implementation
class_addMethod(runtimeSubClass, @selector(description), (IMP)SubMethod, types);
}
void createARuntimeSubClass()
{
//create subclass
runtimeSubClass = objc_allocateClassPair([runtimeSuperClass class], "RuntimeSubClass", 0);
//register the subclass
objc_registerClassPair(runtimeSubClass);
//create an instance of the subclass
instanceOfRuntimeSubClass = [[runtimeSubClass alloc] init];
//the subclass inherited the method from the superclass
NSLog(@"1. call SubClass's method, it will be not yet overridden.");
NSLog([instanceOfRuntimeSubClass description]);
overrideMethodInSubClassByHardEncoding();
NSLog(@"Instance of the SubClass has been created...");
}
void invokeSuperClassMethodFromSubClass()
{
//create a superclass object from the subclass
struct objc_super superClass = {
.receiver = instanceOfRuntimeSubClass,
.super_class = class_getSuperclass([instanceOfRuntimeSubClass class])
};
//call the superclass's method from subclass
NSLog(@"2. call SuperClass's method, from SubClass.");
NSLog(objc_msgSendSuper(&superClass, @selector(description)));
//call the subclass's changed method
NSLog(@"3. call SubClass's overridden method.");
NSLog([instanceOfRuntimeSubClass description]);
}
void checkKindOfSuperClass()
{
NSLog(@"\n");
//check the kind of superclass's instance
if ([instanceOfRuntimeSuperClass isKindOfClass:runtimeSuperClass])
NSLog(@"The type of instanceOfRuntimeSuperclass is RuntimeSuperClass");
else
NSLog(@"The type if instanceOfRuntimeSuperClass is not RuntimeSuperClass");
}
void checkKindOfSubClass()
{
NSLog(@"\n");
//check the kind of subclass's instance
if ([instanceOfRuntimeSubClass isKindOfClass:runtimeSubClass])
NSLog(@"The type of instanceOfRuntimeSubclass is RuntimeSubClass");
else
NSLog(@"The type if instanceOfRuntimeSubClass is not RuntimeSubClass");
}
//check the kind of the given instances
void checkKindsOfInstances()
{
checkKindOfSuperClass();
checkKindOfSubClass();
}
void getMethodsOfClassInstances()
{
NSLog(@"\n");
unsigned int numberOfMethods;
//get the method list of superclass
Method* methods = class_copyMethodList([runtimeSuperClass class], &numberOfMethods);
//print the methods from the list
NSLog(@"The superclass has: %d method(s)", numberOfMethods);
for (int i = 0; i < numberOfMethods; i++)
NSLog(@"Method name: %@", NSStringFromSelector(method_getName(methods[i])));
//get the method list from subclass
methods = class_copyMethodList([runtimeSubClass class], &numberOfMethods);
//print the methods
NSLog(@"The subclass has: %d method(s)", numberOfMethods);
for (int i = 0; i < numberOfMethods; i++)
NSLog(@"Method name: %@", NSStringFromSelector(method_getName(methods[i])));
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
createARuntimeSuperClass();
createARuntimeSubClass();
invokeSuperClassMethodFromSubClass();
checkKindsOfInstances();
getMethodsOfClassInstances();
}
return 0;
}
Szerző: Siklósi Benjamin (2014)
Használt fordító: XCode 5.1
A program a moon buggy játék egy egyszerű klónja. Az interaktív konzolos felülethez pdcurses-t használ.
Windows-on ezt a GNUStep-rendszer shelljében a mingw-get pdcurses-el lehet installálni, ezek után a
pdc34dllw.zip -t kell letölteni
és ebből a .h-kat a GNUStep/include-ba, a .dll-t a GNUStep/bin-be és a .lib-et a GNUStep/lib mappába kell másolni.
A program ez után a mellékelt makefile-al fordítható lesz.