14 berichten aan het bekijken - 1 tot 14 (van in totaal 14)
  • Q:
    Bijdrager
    bare_nature

    Hulp bij stukje code

    Hallo,

    Ik wil er geen geheim van maken dat ik liever werk met Objective-C dan met C en deze voorkeur ligt wellicht aan het feit dat C mij nogal eens de wenkbrauwen doet fronsen.

    In het boek van Jeff Lamarche (More iPhone Development) staat de volgende methode:

    <br />
    - (NSArray *)splitTransferredPackets:(NSData **)leftover {<br />
        NSMutableArray *ret = [NSMutableArray array];<br />
        const unsigned char *beginning = [self bytes];<br />
        const unsigned char *offset = [self bytes];<br />
        NSInteger bytesEnd = (NSInteger)offset + [self length];<br />
    while ((NSInteger)offset < bytesEnd) {<br />
            uint64_t dataSize[1];<br />
            NSInteger dataSizeStart = offset - beginning;<br />
            NSInteger dataStart = dataSizeStart + sizeof(uint64_t);<br />
    NSRange headerRange = NSMakeRange(dataSizeStart, sizeof(uint64_t));<br />
            [self getBytes:dataSize range:headerRange];<br />
    if (dataStart + dataSize[0] + (NSInteger)offset > bytesEnd) {<br />
                NSInteger lengthOfRemainingData = [self length] - dataSizeStart;<br />
                NSRange dataRange = NSMakeRange(dataSizeStart, lengthOfRemainingData);<br />
                *leftover = [self subdataWithRange:dataRange];<br />
    return ret;<br />
            }<br />
    NSRange dataRange = NSMakeRange(dataStart, dataSize[0]);<br />
            NSData *parsedData = [self subdataWithRange:dataRange];<br />
    [ret addObject:parsedData];<br />
            offset = offset + dataSize[0] + sizeof(uint64_t);<br />
        }<br />
        return ret;<br />
    }<br />
     

    Voor alle duidelijkheid, “self” wijst hier naar een instance van NSData. Mijn verwarring komt van twee zaken:

    1) Het gebruik van constanten: Eerst worden er twee pointers gedeclareerd met de inhoud van de NSData instance (*beginning en *offset) en in de vijfde lijn wordt “offset” als een NSInteger gecast en verder gebruikt als een gewone variable. Het is me duidelijk dat het hier niet om een pointer gaat, maar waarom worden “beginning” en “offset” dan initieel als constanten gedeclareerd.?

    2) De tweede onduidelijkheid is het gebruik van C-arrays. Waarom wordt in de eerste regel van de while loop een C-array gebruikt? Is het nodig dat dit een array is met één element?

    Het zijn wellicht evidente zaken, maar als je aan Objective-C gewend bent, is het soms moeilijk om naar C terug te keren.

    Voor ik de gebruikelijke reactie krijg: Ik weet dat ik eerst C grondig onder de knie moet krijgen alvorens met Objective-C te beginnen, maar dit is momenteel mijn situatie.

    Alvast bedankt,

    BN

    Bijdrager
    bitsflew

    maar waarom worden “beginning” en “offset” dan initieel als constanten gedeclareerd.?

    beginning en offset zijn geen constanten maar pointers naar const data, maw read-only.

    BTW Het van een pointer naar NSInteger (signed!) casten en er vervolgens mee gaan rekenen is vragen om problemen.

    Kijk maar eens naar de volgende regel

    <br />
    NSInteger bytesEnd = (NSInteger)offset + [self length];<br />
     

    De code werkt niet goed (hangt) als bytesEnd >= 0x80000000 (32-bit) of bytesEnd >= 0x8000000000000000 (64-bit)

    Is het nodig dat dit een array is met één element?

    Nee, je kunt ook gewoon een variabele gebruiken.

    Aangepaste code inclusief fix voor de pointer berekeningen

    <br />
    - (NSArray *)splitTransferredPackets:(NSData **)leftover {<br />
        NSMutableArray *ret = [NSMutableArray array];<br />
        const unsigned char *beginning = [self bytes];<br />
        const unsigned char *offset = [self bytes];<br />
        NSUInteger bytesEnd = (NSUInteger)offset + [self length];<br />
    while ((NSUInteger)offset < bytesEnd) {<br />
            uint64_t dataSize;<br />
            NSUInteger dataSizeStart = offset - beginning;<br />
            NSUInteger dataStart = dataSizeStart + sizeof(uint64_t);<br />
    NSRange headerRange = NSMakeRange(dataSizeStart, sizeof(uint64_t));<br />
            [self getBytes: &dataSize range:headerRange];<br />
    if (dataStart + dataSize + (NSUInteger)offset > bytesEnd) {<br />
                NSUInteger lengthOfRemainingData = [self length] - dataSizeStart;<br />
                NSRange dataRange = NSMakeRange(dataSizeStart, lengthOfRemainingData);<br />
                *leftover = [self subdataWithRange:dataRange];<br />
    return ret;<br />
            }<br />
    NSRange dataRange = NSMakeRange(dataStart, dataSize);<br />
            NSData *parsedData = [self subdataWithRange:dataRange];<br />
    [ret addObject:parsedData];<br />
            offset = offset + dataSize + sizeof(uint64_t);<br />
        }<br />
        return ret;<br />
    }

    Dezelfde code maar nu netter en zonder pointers.

    - (NSArray *)splitTransferredPackets:(NSData **)leftover {<br />
        NSMutableArray *ret = [NSMutableArray array];<br />
        NSUInteger dataSizeStart = 0;<br />
        NSUInteger bytesEnd = [self length];<br />
    	while (dataSizeStart < bytesEnd) {<br />
            uint64_t dataSize;<br />
            NSUInteger dataStart = dataSizeStart + sizeof(dataSize);<br />
    		NSRange headerRange = NSMakeRange(dataSizeStart, sizeof(dataSize));<br />
            [self getBytes: &dataSize range: headerRange];<br />
    		if (dataStart + dataSize > bytesEnd) {<br />
                NSUInteger lengthOfRemainingData = [self length] - dataSizeStart;<br />
                NSRange dataRange = NSMakeRange(dataSizeStart, lengthOfRemainingData);<br />
                *leftover = [self subdataWithRange:dataRange];<br />
    			return ret;<br />
            }<br />
    		NSRange dataRange = NSMakeRange(dataStart, dataSize);<br />
            NSData *parsedData = [self subdataWithRange:dataRange];<br />
    		[ret addObject:parsedData];<br />
            dataSizeStart = dataSizeStart + dataSize + sizeof(dataSize);<br />
        }<br />
        return ret;<br />
    }<br />
     
    Bijdrager
    bare_nature

    @bitsflew: Erg bedankt om de tijd te nemen om dit even toe te lichten. Het is me al heel wat duidelijker!

    Bijdrager
    Ezri Dax

    [off topic]
    Waarom doet C jou de wenkbrauwen fronsen?
    [/off topic]

    Bijdrager
    dj bazzie wazzie

    Zoals MadDonna al zegt waarom doet C jouw wenkbrauwen fronsen? Ik ben weer aantal weken bezig met een C/C++ project en moet zeggen dat elke keer wanneer ik weer terug ga naar Objective-C mij de wenkbrauwen doet fronsen, namelijk: ‘had de ontwerper geen betere syntax kunnen bedenken?’. Dat is wat ik mij dan elke keer weer afvraag.

    Bijdrager
    bare_nature

    @Maddonna en dj bazzie wazzie: Ik denk dat het te maken heeft waarmee je het meest vertrouwd bent. Persoonlijk vind ik dat Objective-C veel leuker werkt en wellicht heeft dit te maken met het feit dat veel zaken voor je gedaan worden (achter de schermen). Opnieuw, dit is een persoonlijke voorkeur en ik begrijp dat er mensen zijn die het omgekeerde gevoel hebben (zoals dj bazzie wazzie). Aangezien ik met Cocoa werk gebruik ik 90% van de tijd Objective-C en ben ik dus minder gewend om met C te werken (ook als is Obj.-C een superset van C).

    BN

    Bijdrager
    dj bazzie wazzie

    @bare_nature: Daar heb je op zich wel een goed punt. Ik ben van C/C++ naar Objective-C toe gegaan waardoor C/C++ eigenlijk mijn moedertaal is.

    Bijdrager
    Ezri Dax

    Ik snap nou dat je objective c een mooie taal vind, maar niet wat je niet mooi vind aan C.

    Bijdrager
    dj bazzie wazzie

    Ik denk dat dat komt omdat bare_nature en veel andere programmeurs de voorkeur geven aan een makkelijkere taal. Bijvoorbeeld de volgende code in C heb je niet nodig in C++ of Objective-C

    <br />
    size_t varlen = MBstrlen(variabele1);<br />
    wchar_t *variabele2 = malloc(varlen * sizeof(wchar_t) + 1);<br />
    mbstowcs(variabele2, variabele1, strlen(variabele1) + 1);<br />
     

    Wat deze code doet (of zou moeten doen, even snel getypt en niet getest) is de multibyte character variabele1 converteren naar wide character en opslaan in variabele2. Voor veel zal multibyte en wide character niet zoveel verschillen maar je bent het in C echt nodig. Je wil alleen met narrow en wide characters werken en niet met multibyte (UTF-8). Dit soort problemen kom je niet tegen in Object georienteerde talen. De std::string class in C++ en de Cocoa Class NSString lossen al deze problemen voor je op en heb je niets te maken met narrow, wide of multibyte characters. Wanneer je string.length() opvraagt weet je in object georienteerd gewoon hoelang de string is of het nou Russisch (multibyte of wide character) of Nederlands (narrow character) is, het aantal karakters kloppen altijd.

    De keerzijde van dit hele verhaal is natuurlijk wel dat ik persoonlijk C veel uitdagender en puurder vind dan alle andere talen en ik kick op snelheid. Maar ook dat is weer een heel persoonlijk iets.

    Bijdrager
    bare_nature

    @MadDonna: Het is niet dat ik C niet “mooi” vind. Het punt dat dj bazzie wazzie maakt komt dichter in de buurt, denk ik. Ik denk dat we het kunnen houden bij het feit dat ik minder praktijkervaring heb met C dan met Objective-C. Het is een beetje als rijden met een automatische (Objective-C) en een manuele (C) versnellingsbak. De twee doen hun job even goed, laten we zeggen, maar het is voor veel mensen moeilijk om naar een manuele versnellingsbak over te stappen als je gewend bent aan een automatische ;-).

    Een mooie analogie al zeg ik het zelf ;-).

    BN

    Bijdrager
    dj bazzie wazzie

    @bare_nature: Een hele mooie vergelijking:)…. en ik kan mij er wel in vinden. Alleen hoe wat is dan een Applescripter? :sarcastic:

    Bijdrager
    bare_nature

    Een AppleScripter rijdt met een fiets, lijkt me ;-).

    Bijdrager
    arjandemeijer
    <br />
    #import <Cocoa/Cocoa.h><br />
    @interface AantalKarakters : NSObject {<br />
    	IBOutlet NSTextField *tekstvak;<br />
    	IBOutlet NSTextField *tekstlabel;<br />
    }<br />
    -(IBAction)telAantalKarakters:(id)sender;<br />
    @end<br />
     
    <br />
    #import "AantalKarakters.h"<br />
    @implementation AantalKarakters<br />
    -(IBAction)telAantalKarakters:(id)sender<br />
    {<br />
    	NSString *waarde = [NSString stringWithString:[tekstvak stringValue]];<br />
    	NSString *formaat = [[NSString alloc] initWithFormat:@" ' %@ ', heeft %i karakter(s)" , [waarde init] , [waarde length]];<br />
    	[tekstlabel setStringValue:[formaat init]];<br />
    }<br />
    @end<br />
     

    Mijn probleem

    Ben bezig met een newbie oefening uit het boek ‘Cocoa programming for Mac OSX’ en daar staat een challenge in voor de lezer.

    De challenge is om het aantal karakters in een tekstveld als getal toe te wijzen aan een label, als er door de gebruiker op de knop (count characters) wordt gedrukt.

    Nu werkt mijn bovenstaande code helemaal en dat is verder het probleem niet, alleen vraag me sterk af of ik nu wel efficiënt aan het programmeren ben!

    Aangezien ik bij het object “formaat” de eerste keer ‘initWithFormat’ gebruik en daarna de tweede keer de waarde op ga vragen via ‘init’

    Bijdrager
    Verwijder

    De code kan inderdaad efficiënter. init hoef je alleen aan te roepen bij objecten die je zelf aanmaakt met alloc, niet bij objecten die al bestaan omdat je ze bijvoorbeeld als resultaat van een method terugkrijgt. Ook is het meestal niet nodig een kopie van een string te maken.

    -(IBAction)telAantalKarakters:(id)sender<br />
    {<br />
    	NSString *waarde = [tekstvak stringValue];<br />
    	NSString *formaat = [[NSString alloc] initWithFormat:@" ' %@ ', heeft %i karakter(s)", waarde, [waarde length]];<br />
    	[tekstlabel setStringValue:formaat];<br />
    }<br />
    @end

    Als garbage collection niet aan staat dan moet alles wat met alloc wordt aangemaakt ook weer worden gereleased. Een alternatief is een class method gebruiken die een ge-autoreleased object teruggeeft, dat leest ook wat makkelijker vind ik. Het tweede statement wordt dan:

    NSString *formaat = [NSString stringWithFormat:@" ' %@ ', heeft %i karakter(s)", waarde, [waarde length]];

    Het is mogelijk om het resultaat van een method direct als parameter te gebruiken. Het is wat korter maar debugt moeilijker en is soms minder leesbaar.

    [tekstlabel setStringValue:[NSString stringWithFormat:@" ' %@ ', heeft %i karakter(s)", waarde, [waarde length]]];
14 berichten aan het bekijken - 1 tot 14 (van in totaal 14)

Je moet ingelogd zijn om een reactie op dit onderwerp te kunnen geven.