Today Extension und CoreData

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • 1. Im Regelfall benötige ich genau einen Core-Data-Stack. Templates sind für den Regelfall gedacht und verbauen hier rein gar nichts. Dann ist es absolut richtig, dass im ohnehin als Singleton vorhanden AppDelegate zu machen, anstelle eine weitere Klasse ins Projekt zu legen, die dann für den Regelfall wieder nur instantiert werden muss, einschließlich der Pflege der Lebensdauer, was dann mutmaßlich ohnehin wieder das AppDelegate machen würde. Das ist unnötig verkomplizierend.

    2. Das AppDelegate ist eigentlich immer vorhanden. Eine Abhängigkeit hierhin ist also eine Abhängigkeit zu einer generischen Klasse, die unschädlich ist. Ich abstrahiere ja auch nicht eine Abhängigkeit zu NSArray oder NSString weg. Eine eigene Klasse CoreDataStack würde ebenso eine Abhängigkeit erzeugen. Zu wiederum einer – im besten Falle – generischen Klasse. Gewinn: 0.

    Dass jemand in Probleme kommt, die mit mehr als minimalen Aufwand zu lösen wären, weil eine Abhängigkeit vom AppDelegate besteht, ist fernliegend.

    Übrigens: Wenn man die Projektstruktur ändern muss, weil etwa mehrere Kontexte in einer Applikation existieren – etwa Dokumenten basierte Applikationen – so existiert dafür bereits die Abstraktion NSManagedObjectContext. Ich muss diese Abstraktion nicht erneut abstrahieren.

    3. Die Angst vor zu großen Klassen verstehe ich nicht:

    3.1. Entweder gehört etwas strukturell zu einer Klasse, dann gehört es strukturell zu dieser Klasse. Oder eben nicht. Das hat etwas mit Struktur zu tun, nicht mit Größe. Sie in Subklassen zu zerlegen, die dann genau den Zweck haben, eine Thematik der Klasse zu behandeln, strukturiert etwas, was nicht strukturiert werden muss. Man landet hier häufig in dem Antipattern, dass Objekte nicht Verantwortungsbereiche darstellen, sondern Module. Module sind keine Klassen oder Objekte.

    3.2. Objective-C kennt Kategorien. Wenn einem also etwas zu unübersichtlich wird, kann man dazu greifen. Wir sind ja hier nicht bei Java.

    3.3. Wie sieht es eigentlich mit der Angst vor zu großen Projekten aus?

    Das ist hier besonders auffällig. Du würdest den im AppDelegate vorhandenen Code 1:1 kopieren. (Daher meine obige Frage.) Parameterliste würden sich nicht verändern, Daten müssten aus dem App(!)-Bundle geladen werden. (Vorsicht: Abhängigkeit!) Das zeigt, dass es nicht um Verantwortung, sondern Modularisierung geht.

    Insgesamt: Die einfachste und intuitivste Sache Sache der Welt wird durch theoretisierende Überlegungen verkompliziert. Man kann das natürlich lösen, indem man der Klasse dann noch einen Bundle-Namen mitgibt oder – richtig schön theoretisierend kaputt gemacht – man ein Protokoll definiert, das die API beschreibt und dann noch ein Protokoll für Delegate einbaut, welches die notwendigen Daten wie Bundle-Name holt.

    Und wozu gleich noch?
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von Amin Negm-Awad ()

  • Amin Negm-Awad schrieb:

    1. Im Regelfall benötige ich genau einen Core-Data-Stack. Templates sind für den Regelfall gedacht und verbauen hier rein gar nichts. Dann ist es absolut richtig, dass im ohnehin als Singleton vorhanden AppDelegate zu machen, anstelle eine weitere Klasse ins Projekt zu legen, die dann für den Regelfall wieder nur instantiert werden muss, einschließlich der Pflege der Lebensdauer, was dann mutmaßlich ohnehin wieder das AppDelegate machen würde. Das ist unnötig verkomplizierend.

    2. Das AppDelegate ist eigentlich immer vorhanden. Eine Abhängigkeit hierhin ist also eine Abhängigkeit zu einer generischen Klasse, die unschädlich ist. Ich abstrahiere ja auch nicht eine Abhängigkeit zu NSArray oder NSString weg. Eine eigene Klasse CoreDataStack würde ebenso eine Abhängigkeit erzeugen. Zu wiederum einer – im besten Falle – generischen Klasse. Gewinn: 0.

    Dass jemand in Probleme kommt, die mit mehr als minimalen Aufwand zu lösen wären, weil eine Abhängigkeit vom AppDelegate besteht, ist fernliegend.

    Übrigens: Wenn man die Projektstruktur ändern muss, weil etwa mehrere Kontexte in einer Applikation existieren – etwa Dokumenten basierte Applikationen – so existiert dafür bereits die Abstraktion NSManagedObjectContext. Ich muss diese Abstraktion nicht erneut abstrahieren.

    3. Die Angst vor zu großen Klassen verstehe ich nicht:

    3.1. Entweder gehört etwas strukturell zu einer Klasse, dann gehört es strukturell zu dieser Klasse. Oder eben nicht. Das hat etwas mit Struktur zu tun, nicht mit Größe. Sie in Subklassen zu zerlegen, die dann genau den Zweck haben, eine Thematik der Klasse zu behandeln, strukturiert etwas, was nicht strukturiert werden muss. Man landet hier häufig in dem Antipattern, dass Objekte nicht Verantwortungsbereiche darstellen, sondern Module. Module sind keine Klassen oder Objekte.

    3.2. Objective-C kennt Kategorien. Wenn einem also etwas zu unübersichtlich wird, kann man dazu greifen. Wir sind ja hier nicht bei Java.

    3.3. Wie sieht es eigentlich mit der Angst vor zu großen Projekten aus?

    Das ist hier besonders auffällig. Du würdest den im AppDelegate vorhandenen Code 1:1 kopieren. (Daher meine obige Frage.) Parameterliste würden sich nicht verändern, Daten müssten aus dem App(!)-Bundle geladen werden. (Vorsicht: Abhängigkeit!) Das zeigt, dass es nicht um Verantwortung, sondern Modularisierung geht.

    Insgesamt: Die einfachste und intuitivste Sache Sache der Welt wird durch theoretisierende Überlegungen verkompliziert. Man kann das natürlich lösen, indem man der Klasse dann noch einen Bundle-Namen mitgibt oder – richtig schön theoretisierend kaputt gemacht – man ein Protokoll definiert, das die API beschreibt und dann noch ein Protokoll für Delegate einbaut, welches die notwendigen Daten wie Bundle-Name holt.

    Und wozu gleich noch?
    Bitte sag mir doch, an welcher Stelle ich dem TE empfohlen habe, es "richtig schön theoretisierend kaputt" zu machen, da bin ich gespannt. Java hast Du ins Spiel gebracht. Aber da Du mir offensichtlich bis hier hin nicht folgen kannst, hier der Code:

    Quellcode

    1. @interface MKMCoreDataStack : NSObject
    2. @property (nonatomic, strong, readonly) NSManagedObjectContext *managedObjectContext;
    3. @property (nonatomic, strong, readonly) NSManagedObjectContext *rootContext;
    4. - (instancetype)initWithModel:(NSManagedObjectModel*)model storeURL:(NSURL*)store storeType:(NSString*)storeType options:(NSDictionary*)options;
    5. - (instancetype)initWithModelURL:(NSURL*)modelURL storeURL:(NSURL*)store storeType:(NSString*)storeType options:(NSDictionary*)options;
    6. - (void)saveWithCompletionHandler:(void(^)(void))completionHandler errorHandler:(void(^)(NSError*))errorHandler;
    7. - (NSManagedObjectContext*)newPrivateContext;
    8. @end
    Alles anzeigen

    Das ist alles nur sinnloser boilerplate code, der in jedem Projekt gleich aussieht. Es macht für mich daher Sinn, das zu kapseln und nicht immer wieder neu runter zu schreiben - und ich habe durch Tests die Gewissheit, dass Apple nicht in der nächste Xcode-Version irgendwas kaputt macht. Im AppDelegate wird der Stack mit der Model-URL und der StoreURL erzeugt und fertig. Es wird auch nicht der Stack rumgereicht, sondern natürlich die entsprechenden Kontexte. Für Deine Tests musst Du auch einen Stack aufsetzen, da kannst Du natürlich gerne Dein AppDelegate instanziieren, ist ja die einfachste und intuitivste Sache der Welt...

    Aber dieser Thread ist mal wieder ein schönes Beispiel dafür, wie es so oft in diesem Forum abläuft. Jemand stellt eine Frage, es gibt ein paar Antworten und binnen kürzester Zeit schweifen die Threads in sinnlose, nervenaufreibende Diskussionen und Haarspaltereien ab.

    Aber ich habe ja schon weiter oben geschrieben, dass es jeder machen soll, wie er es für richtig hält.

    Gruß, Markus
  • Und hier noch die Tests:

    Smarty-Template

    1. #import <XCTest/XCTest.h>
    2. #import "MKMCoreDataStack.h"
    3. static const NSTimeInterval kTimeout = 10;
    4. @interface MKMCoreDataStackTests : XCTestCase
    5. @property (nonatomic, strong) NSURL *storeURL;
    6. @property (nonatomic, strong) NSString *storeType;
    7. @property (nonatomic, strong) NSDictionary *storeOptions;
    8. @property (nonatomic, strong) NSURL *modelURL;
    9. @end
    10. @implementation MKMCoreDataStackTests
    11. {
    12. MKMCoreDataStack *sut;
    13. }
    14. - (void)setUp
    15. {
    16. [super setUp];
    17. self.storeURL = [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:@"fixture.store"];
    18. self.storeType = NSInMemoryStoreType;
    19. self.modelURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"MKMCoreDataStackTestModel"
    20. withExtension:@"momd"];
    21. self.storeOptions = @{NSReadOnlyPersistentStoreOption: @YES};
    22. sut = [[MKMCoreDataStack alloc] initWithModelURL:self.modelURL
    23. storeURL:self.storeURL
    24. storeType:self.storeType
    25. options:nil];
    26. }
    27. - (NSManagedObjectModel*)createTestModel
    28. {
    29. NSManagedObjectModel *model = [[NSManagedObjectModel alloc] init];
    30. NSEntityDescription *entity = [[NSEntityDescription alloc] init];
    31. [entity setName:@"Entity"];
    32. NSAttributeDescription *attribute = [[NSAttributeDescription alloc] init];
    33. [attribute setName:@"title"];
    34. [attribute setAttributeType:NSStringAttributeType];
    35. [entity setProperties:@[attribute]];
    36. [model setEntities:@[entity]];
    37. return model;
    38. }
    39. - (NSManagedObjectModel*)createTestModelWithNonOptionalValue
    40. {
    41. NSManagedObjectModel *model = [[NSManagedObjectModel alloc] init];
    42. NSEntityDescription *entity = [[NSEntityDescription alloc] init];
    43. [entity setName:@"Entity"];
    44. NSAttributeDescription *attribute = [[NSAttributeDescription alloc] init];
    45. [attribute setName:@"title"];
    46. [attribute setOptional:NO];
    47. [attribute setAttributeType:NSStringAttributeType];
    48. [entity setProperties:@[attribute]];
    49. [model setEntities:@[entity]];
    50. return model;
    51. }
    52. - (void)givenTheContextHasChanges:(NSManagedObjectContext*)moc
    53. {
    54. [moc performBlockAndWait:^{
    55. NSManagedObject *mo = [NSEntityDescription insertNewObjectForEntityForName:@"Entity"
    56. inManagedObjectContext:moc];
    57. [mo setValue:@"A title" forKey:@"title"];
    58. }];
    59. }
    60. - (void)testThatItRaisesWhenInitializedWithNilModel {
    61. XCTAssertThrowsSpecificNamed([[MKMCoreDataStack alloc] initWithModel:nil storeURL:[NSURL URLWithString:@""] storeType:NSInMemoryStoreType options:nil], NSException, NSInternalInconsistencyException);
    62. }
    63. - (void)testThatItRaisesWhenInitalizedWithNilStore {
    64. XCTAssertThrowsSpecificNamed([[MKMCoreDataStack alloc] initWithModel:[[NSManagedObjectModel alloc] init]
    65. storeURL:nil
    66. storeType:NSInMemoryStoreType
    67. options:nil], NSException, NSInternalInconsistencyException);
    68. }
    69. - (void)testThatItRaisesWhenInitializedWithNilModelURL {
    70. XCTAssertThrowsSpecificNamed([[MKMCoreDataStack alloc] initWithModelURL:nil
    71. storeURL:nil
    72. storeType:NSInMemoryStoreType options:nil], NSException, NSInternalInconsistencyException);
    73. }
    74. - (void)testThatItCanCreateACoreDataStackFromAModelURL {
    75. sut = [[MKMCoreDataStack alloc] initWithModelURL:self.modelURL
    76. storeURL:self.storeURL
    77. storeType:self.storeType
    78. options:self.storeOptions];
    79. XCTAssertNotNil(sut.managedObjectContext);
    80. XCTAssertEqual(sut.managedObjectContext.concurrencyType, NSMainQueueConcurrencyType);
    81. XCTAssertEqual(sut.managedObjectContext.parentContext.concurrencyType, NSPrivateQueueConcurrencyType);
    82. XCTAssertNotNil(sut.managedObjectContext.parentContext.persistentStoreCoordinator);
    83. NSPersistentStore *store = [sut.managedObjectContext.parentContext.persistentStoreCoordinator.persistentStores firstObject];
    84. XCTAssertEqualObjects([store URL], self.storeURL);
    85. XCTAssertEqualObjects([store type], self.storeType);
    86. XCTAssertEqualObjects(store.options, self.storeOptions);
    87. }
    88. - (void)testThatItCanCreateACoreDataStackFromAModel {
    89. sut = [[MKMCoreDataStack alloc] initWithModel:[self createTestModel]
    90. storeURL:self.storeURL
    91. storeType:self.storeType
    92. options:self.storeOptions];
    93. XCTAssertNotNil(sut.managedObjectContext);
    94. XCTAssertEqual(sut.managedObjectContext.concurrencyType, NSMainQueueConcurrencyType);
    95. XCTAssertEqual(sut.managedObjectContext.parentContext.concurrencyType, NSPrivateQueueConcurrencyType);
    96. XCTAssertNotNil(sut.managedObjectContext.parentContext.persistentStoreCoordinator);
    97. NSPersistentStore *store = [sut.managedObjectContext.parentContext.persistentStoreCoordinator.persistentStores firstObject];
    98. XCTAssertEqualObjects([store URL], self.storeURL);
    99. XCTAssertEqualObjects([store type], self.storeType);
    100. XCTAssertEqualObjects(store.options, self.storeOptions);
    101. }
    102. - (void)testThatItSavesWhenMainContextTheContextHasChanges {
    103. sut = [[MKMCoreDataStack alloc] initWithModelURL:self.modelURL
    104. storeURL:self.storeURL
    105. storeType:self.storeType
    106. options:nil];
    107. [self givenTheContextHasChanges:sut.managedObjectContext];
    108. XCTestExpectation *saveErrorExpectation = [self expectationWithDescription:@"save error is nil expectation"];
    109. [sut saveWithCompletionHandler:^ {
    110. [saveErrorExpectation fulfill];
    111. } errorHandler:nil];
    112. [self waitForExpectationsWithTimeout:kTimeout handler:^(NSError *error) {
    113. XCTAssertFalse(sut.managedObjectContext.hasChanges);
    114. XCTAssertFalse(sut.managedObjectContext.parentContext.hasChanges);
    115. }];
    116. }
    117. - (void)testThatItSavesWhenRootContextTheContextHasChanges {
    118. sut = [[MKMCoreDataStack alloc] initWithModelURL:self.modelURL
    119. storeURL:self.storeURL
    120. storeType:self.storeType
    121. options:nil];
    122. XCTestExpectation *saveErrorExpectation = [self expectationWithDescription:@"save error is nil expectation"];
    123. NSManagedObjectContext *testContext = sut.managedObjectContext.parentContext;
    124. [self givenTheContextHasChanges:testContext];
    125. [sut saveWithCompletionHandler:^ {
    126. [saveErrorExpectation fulfill];
    127. } errorHandler:nil];
    128. [self waitForExpectationsWithTimeout:kTimeout handler:^(NSError *error) {
    129. XCTAssertFalse(testContext.hasChanges);
    130. }];
    131. }
    132. - (void)testThatTheErrorHandlerIsInvokedOnSaveWhenAnErrorOccurs {
    133. sut = [[MKMCoreDataStack alloc] initWithModel:[self createTestModelWithNonOptionalValue]
    134. storeURL:self.storeURL
    135. storeType:self.storeType
    136. options:nil];
    137. XCTestExpectation *saveErrorExpectation = [self expectationWithDescription:@"save error is nil expectation"];
    138. [NSEntityDescription insertNewObjectForEntityForName:@"Entity"
    139. inManagedObjectContext:sut.managedObjectContext];
    140. __block NSError *saveError = nil;
    141. [sut saveWithCompletionHandler:nil errorHandler:^(NSError *error) {
    142. saveError = error;
    143. [saveErrorExpectation fulfill];
    144. }];
    145. [self waitForExpectationsWithTimeout:kTimeout handler:^(NSError *error) {
    146. XCTAssertNotNil(saveError);
    147. }];
    148. }
    149. - (void)testThatItHasARootContextWithAPrivateConcurrencyType {
    150. XCTAssertNotNil(sut.rootContext);
    151. XCTAssertEqual(sut.rootContext.concurrencyType, NSPrivateQueueConcurrencyType);
    152. XCTAssertNotNil(sut.rootContext.persistentStoreCoordinator);
    153. }
    154. - (void)testPrivateContextCreation
    155. {
    156. NSManagedObjectContext *context = [sut newPrivateContext];
    157. XCTAssertNotNil(context);
    158. XCTAssertEqual(context.concurrencyType, NSPrivateQueueConcurrencyType);
    159. XCTAssertNotNil(context.parentContext);
    160. XCTAssertEqualObjects(context.parentContext, sut.rootContext);
    161. }
    162. @end
    Alles anzeigen
    @Admins: ich komme mit diesem Code-Editor nicht klar. Was muss ich eingeben, damit Objective-C Code vernünftig formatiert wird? Ich das oben in [code]-Klammern gesetzt und direkt von Xcode mit copy&paste eingefügt, jetzt sind alle Einrückungen weg...
  • Du hast sinnloses Theoretisieren nicht empfohlen, sondern gemacht.

    Und der Boilerplate-Code stünde doch exact genau so in CoreDataStack. Genau deshalb habe ich ja gefragt, was du denn in CoreDataStack haben willst. Übrigens ist es kein Boilerplate-Code. Dieser ist definiertes sich immer wiederholender, nicht eigentlich funktionaler Code. Der Code taucht genau einmal im Template auf und iss nicht einmal von dir eingegeben werden. Er hat eine zentrale Funktion.

    Du bist übrigens ins Sinnlose abgeschweift, weil du das Fass aufgemacht hast, wie sinnvoll das Template ist. Das hatte der OP nicht gefragt.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Amin Negm-Awad ()

  • Wie auch immer! Ich schreibe jetzt zum dritten Mal, dass es jeder machen soll, wie er es für richtig hält. Jedenfalls habe ich, im Gegensatz zu Dir, dem TE eine Lösung für sein Problem genannt. Viele Wege führen nach Rom. Habe jetzt auch keine Lust mehr, mich mit Dir rumzustreiten, bringt eh nix - hab ich ja ebenfalls weiter oben geschrieben...q.e.d.
  • Markus Müller schrieb:

    Wie auch immer! Ich schreibe jetzt zum dritten Mal, dass es jeder machen soll, wie er es für richtig hält. Jedenfalls habe ich, im Gegensatz zu Dir, dem TE eine Lösung für sein Problem genannt. Viele Wege führen nach Rom. Habe jetzt auch keine Lust mehr, mich mit Dir rumzustreiten, bringt eh nix - hab ich ja ebenfalls weiter oben geschrieben...q.e.d.
    Ich habe dir nicht verboten, es so zu machen, wie du es möchtest. Ich habe mir lediglich die Freiheit herausgenommen zu sagen, dass ich das für nicht richtig halte. *Schulterzuck* Wenn du keine abweichende Meinungen zu deinen Ratschlägen hören möchtest, solltest du sie vielleicht per PM oder E-Mail erteilen.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Amin Negm-Awad schrieb:

    Markus Müller schrieb:

    Wie auch immer! Ich schreibe jetzt zum dritten Mal, dass es jeder machen soll, wie er es für richtig hält. Jedenfalls habe ich, im Gegensatz zu Dir, dem TE eine Lösung für sein Problem genannt. Viele Wege führen nach Rom. Habe jetzt auch keine Lust mehr, mich mit Dir rumzustreiten, bringt eh nix - hab ich ja ebenfalls weiter oben geschrieben...q.e.d.
    Ich habe dir nicht verboten, es so zu machen, wie du es möchtest. Ich habe mir lediglich die Freiheit herausgenommen zu sagen, dass ich das für nicht richtig halte. *Schulterzuck* Wenn du keine abweichende Meinungen zu deinen Ratschlägen hören möchtest, solltest du sie vielleicht per PM oder E-Mail erteilen.
    Es geht hier nicht um abweichende Meinungen, sondern darum, dass der TE mit dem Template nicht weiter kommt in seiner App-Extension. Dafür habe ich eine Lösung angeboten und im Verlauf unserer Diskussion ein paar Argumente geschrieben, warum ich das so mache, wie ich es mache. Und ich finde die Xcode Templates schlecht, sowohl mit dem CoreData Kram wie auch mit den TableView-Templates. Du siehst das anders, alles gut! (ich vermute, ich habe die Tendenz zum overengineering und verliere damit manchmal den pragmatischen Blick auf die einfachste Lösung).

    Gruß, Markus

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Markus Müller ()

  • gandhi schrieb:

    Bei der DataSource z.B. finde ich, dass das nicht unbedingt in denViewController gehört. Das erschwert die Wiederverwendung. Klar, oftmals kann man alles in den ViewController packen und das passt dann auch.
    Gerade die Datenquelle – eigentlich sollte sie eher Viewquelle heißen – macht doch genau das, was die Aufgab des Viewcontrollers ist: Views erzeugen und für die Anzeige vorbereiten.
    „Meine Komplikation hatte eine Komplikation.“
  • Markus Müller schrieb:

    Amin Negm-Awad schrieb:

    Markus Müller schrieb:

    Wie auch immer! Ich schreibe jetzt zum dritten Mal, dass es jeder machen soll, wie er es für richtig hält. Jedenfalls habe ich, im Gegensatz zu Dir, dem TE eine Lösung für sein Problem genannt. Viele Wege führen nach Rom. Habe jetzt auch keine Lust mehr, mich mit Dir rumzustreiten, bringt eh nix - hab ich ja ebenfalls weiter oben geschrieben...q.e.d.
    Ich habe dir nicht verboten, es so zu machen, wie du es möchtest. Ich habe mir lediglich die Freiheit herausgenommen zu sagen, dass ich das für nicht richtig halte. *Schulterzuck* Wenn du keine abweichende Meinungen zu deinen Ratschlägen hören möchtest, solltest du sie vielleicht per PM oder E-Mail erteilen.
    Es geht hier nicht um abweichende Meinungen, sondern darum, dass der TE mit dem Template nicht weiter kommt in seiner App-Extension. Dafür habe ich eine Lösung angeboten und im Verlauf unserer Diskussion ein paar Argumente geschrieben, warum ich das so mache, wie ich es mache. Und ich finde die Xcode Templates schlecht, sowohl mit dem CoreData Kram wie auch mit den TableView-Templates. Du siehst das anders, alles gut! (ich vermute, ich habe die Tendenz zum overengineering und verliere damit manchmal den pragmatischen Blick auf die einfachste Lösung).
    Gruß, Markus
    Und ich finde die Templates gut und habe dafür Argumente geschrieben. Eben deshalb ist alles gut.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?