8 berichten aan het bekijken - 1 tot 8 (van in totaal 8)
  • Q:
    Bijdrager
    Jakko Westerbeke

    Swift: „Optional(…)” in uitvoer

    Ik zit een beetje te spelen met Swift, om te zien of ik dat makkelijker onder de knie zal kunnen krijgen dan Objective-C, en ik kom iets tegen waar ik geen oplossing voor vind, en die ook met geen mogelijkheid via Google te vinden is om redenen die hopelijk duidelijk zullen zijn …

    Wat ik in elkaar heb zitten knutselen, is een stukje code dat de inhoud van een directory in een array steekt (via contentsOfDirectoryAtURL() van een NSFileManager) en dan uitvoert naar een TextView. Enig probleem is dat die uitvoer er dan zo uitziet:

    Optional(file:///Users/jakko/Desktop/)

    Wat ik wil zien is natuurlijk alleen file:///Users/jakko/Desktop/ zonder dat Optional() eromheen, maar ik kan met geen mogelijkheid uitvogelen hoe ik dat voor elkaar krijg — en juist omdat optionals zo’n „ding” zijn in Swift heb ik niks aan Google, want het enige dat ik daarmee vind is uitleg over wat optionals zijn, hoe je ze gebruikt, enzovoort.

    Het lijkt erop dat het aan de contentsOfDirectoryAtURL() ligt, dat optionals geeft? Als ik namelijk iets probeer als

    var a:String="foo"
    println(a)

    dar geeft dat foo terug, maar

    var a:String?="foo"
    println(a)

    dan is de uitvoer Optional(“foo”)

    Maar hoe krijg ik dan contentsOfDirectoryAtURL() zover dat ik geen optionals meer in m’n array heb?

    Bijdrager
    Vincentbosch

    Optional() betekent dat Swift niet zeker weet of jouw string daadwerkelijk een string value heeft. Je kunt dit forceren door een “!” achter je variabele te zetten of deze als :String te definiëren, of een nieuwe variabele introduceren met de waardes van je vorige variabele met String(naamVorigeVariabele)

    Voorbeeld:

    var int = 3 –> geeft 3

    var intwordtstring = String(int)

    println(intwordtstring) –> geeft “3”

    **Zelf ben ik ook nog volop Swift lerende, dus correct me if I’m wrong, maar dit zou moeten kloppen.**

    Bijdrager
    TheBigZ

    Precies deze vraag wordt beantwoord door Paul Hegarty in zijn eerste demo.
    Bekijk de video’s, aanrader!

    Stanford biedt gratis cursus Swift

    Bijdrager
    Jakko Westerbeke
    Vincentbosch op 28 januari 2015

    Optional() betekent dat Swift niet zeker weet of jouw string daadwerkelijk een string value heeft. Je kunt dit forceren door een “!” achter je variabele te zetten of deze als :String te definiëren, of een nieuwe variabele introduceren met de waardes van je vorige variabele met String(naamVorigeVariabele)

    Heb ik allemaal geprobeerd, en dat werkt niet:( Maak ik met de hand een array met strings erin, dan werkt het inderdaad zoals je zegt:

    var foo:String? = "foo"
    var bar:String = "bar"
    var inhoud = [foo, bar]
    for item in inhoud {
    	var uitvoer=item!
    	tekst.string = tekst.string! + „\(uitvoer)\n"
    }

    geeft inderdaad geen „Optional(…)” in de uitvoer. Zodra ik het uitroepteken achter var p=item weghaal, wel. Maar probeer ik dit:

    var inhoud:Array = fileManager.contentsOfDirectoryAtURL(pad.URL!, includingPropertiesForKeys: [NSURLPathKey], options:nil, error:nil)!
    for item in inhoud {
    	var uitvoer = item.absoluteString
    	tekst.string = tekst.string! + "\(uitvoer)\n"
    }

    dan komt het er wel bij, en zet ik ! achter item.absoluteString dan maakt dat niks uit. Maar nog wat experimenteren leert me dat dit wel werkt:

    var inhoud:Array = fileManager.contentsOfDirectoryAtURL(pad.URL!, includingPropertiesForKeys: [NSURLPathKey], options:nil, error:nil)!
    for item in inhoud {
    	var uitvoer = item.absoluteString!
    	tekst.string = tekst.string! + "\(uitvoer!)\n"
    }

    met dus een ! achter zowel item.absoluteString! als uitvoer! — laat ik er één van de twee weg dan werkt het niet, en evenmin als ik item.absoluteString! rechtstreeks in de TextView wil wegschrijven. Ik snap er de ballen van waarom, en waarvoor dit „uitpakken” sowieso goed is, maar goed, dat zal wel aan mij liggen zal ik dan maar denken …

    TheBigZ op 28 januari 2015

    Precies deze vraag wordt beantwoord door Paul Hegarty in zijn eerste demo.
    Bekijk de video’s, aanrader!

    Een uur en acht minuten?! Hoe moet ik daar ooit in vinden wat ik wil weten zonder dat hele ding te moeten bekijken … ? Voor wie dit ook zoekt, mm okay: begin te kijken op zo’n 12 minuten voor het einde, okay, alles wat daarvoor zit weet je, mm okay, zo te zien al als je dit probleem tegengekomen bent, okay?:)

    Bijdrager
    TheBigZ
    Jakko op 29 januari 2015
    TheBigZ op 28 januari 2015

    Precies deze vraag wordt beantwoord door Paul Hegarty in zijn eerste demo.
    Bekijk de video’s, aanrader!

    Een uur en acht minuten?! Hoe moet ik daar ooit in vinden wat ik wil weten zonder dat hele ding te moeten bekijken … ? Voor wie dit ook zoekt, mm okay: begin te kijken op zo’n 12 minuten voor het einde, okay, alles wat daarvoor zit weet je, mm okay, zo te zien al als je dit probleem tegengekomen bent, okay?:)

    Je kijkt natuurlijk niet alleen maar naar de Stanford video’s om alleen over Optional te leren.:-D

    Voor iedereen die met Swing wil beginnen is de hele cursus een aanrader. Vandaar de tip.

    Bijdrager
    Jakko Westerbeke

    Ja, ik keek er alleen naar voor dat stukje — ik ben door de rest heengeklikt omdat ik er zo snel niks in ontdekte dat ik nog niet wist, en ook omdat z’n constante ge-okay me op de zenuwen ging werken. (Inderdaad, ik heb er vroeger op school ook nooit veel van gebakken omdat ik er m’n aandacht niet bij kon houden:) ) Komt bij dat ik niet houd van naar video’s kijken om ergens instructie in te krijgen: ik lees het liever op een pagina, dat vind ik veel makkelijker. Maar hoe dan ook wel bedankt voor de tip, want z’n uitleg verhelderde wel een paar dingen voor me die ik tot dan toe niet goed doorhad.

    Verder: toen ik m’n vorige bericht hierboven geplaatst had bedacht ik me ineens dat het wellicht wel in één regel te doen zo zijn, en inderdaad:

    var inhoud:Array = fileManager.contentsOfDirectoryAtURL(pad.URL!, includingPropertiesForKeys: [NSURLPathKey], options:nil, error:nil)!
    for item in inhoud {
        tekst.string = tekst.string! + "\(item.absoluteString!!)\n”
    }

    werkt — dus met twee uitroeptekens na elkaar. Door die ingeving begrijp ik (denk ik) ook wat er aan de hand is: niet alleen zijn de NSURL’s in de array optionals die uitgepakt moeten worden, maar ze moeten ook naar strings omgezet worden. Met één uitroepteken bereik je maar één van die dingen (welke heb ik niet uitgezocht), dus moet er een tweede na om ook de andere stap te doen.

    Bijdrager
    rsluman

    Jacco, je bent dicht in de buurt met je laatste ingeving.

    De methode contentsOfDirectoryAtURL: retourneert een optional array. Die moet je dus eerst ‘uitpakken’.
    Die optional array bevat één of meer NSURL-objecten. De methode absoluteString: retourneert ook weer een optional, die je dus ook moet uitpakken.

    De manier die jij gebruikt:

     
    var inhoud:Array = fileManager.contentsOfDirectoryAtURL(pad.URL!, includingPropertiesForKeys: [NSURLPathKey], options:nil, error:nil)!
     

    (Dus het stukje inhoud:Array) bevat twee foutjes.

    1. Je kent het foute datatype toe: een Array terwijl je een optional array van NSURLs moet toekennen.
    2. Het toekennen van een datatype op deze manier is niet heel netjes en wordt heel subtiel ‘bad programming style’ genoemd (heb ik ook niet bedacht).

    De juiste manier is via casting. De methode contentsOfDirectoryAtURL: geeft een array terug, die je als volgt cast naar een optional array met NSURLs

     
    var inhoud = fileManager.contentsOfDirectoryAtURL(pad, includingPropertiesForKeys: [NSURLPathKey], options:nil, error:nil) as? [NSURL]
     

    In swift cast je door achter de variabelenaam ‘as’ te zetten, gevolgd door het gewenste datatype. De variabele waaraan je iets toewijst, krijgt dan automatisch dat datatype (wat in Swift ‘type inferring’ wordt genoemd). Met as cast je, met as? cast je naar een optional.

    Dan heb je in inhoud dus een optional array staan. Om die uit te pakken, gebruik je iets dat forced unwrapping heet:

     
    if var inhoud = fileManager.contentsOfDirectoryAtURL(pad, includingPropertiesForKeys: [NSURLPathKey], options:nil, error:nil) as? [NSURL]? {
    // ...
    }
     
     

    Binnen het codeblok heb je nu een unwrapped (‘uitgepakte’) array met NSURLs. Daar wil je een string van maken, dus zo:

     
    		for item in inhoud {	// inhoud is niet langer een optional array
    			if let uitvoer = item.absoluteString {		// forced unwrapping
    				tekst.text = tekst.text! + "\(uitvoer)\n"
     
     

    Je complete blok wordt dus:

     
    if var inhoud = fileManager.contentsOfDirectoryAtURL(pad, includingPropertiesForKeys: [NSURLPathKey], options:nil, error:nil) as? [NSURL] {
    	for item in inhoud {	// inhoud is niet langer een optional array
    		if let uitvoer = item.absoluteString {		// forced unwrapping
    			tekst.text = tekst.text! + "\(uitvoer)\n"
    			println(tekst.text) // debug;)
    		}
    	}
    }
     

    (Ik weet niet precies wat tekst voor object is, dus ik heb er maar even een UITextField van gemaakt, vandaar de .text-property.)

    Hoop dat je hier iets aan hebt!

    Bijdrager
    Jakko Westerbeke
    rsluman op 30 januari 2015

    Jacco

    Ik zal er maar vanuitgaan dat je het tegen mij hebt, omdat ik deze thread geopend heb:)

    rsluman op 30 januari 2015

    De methode contentsOfDirectoryAtURL: retourneert een optional array. Die moet je dus eerst ‘uitpakken’.
    Die optional array bevat één of meer NSURL-objecten. De methode absoluteString: retourneert ook weer een optional, die je dus ook moet uitpakken.

    Ja, precies, dat realiseerde ik me ook op den duur. Dat ik er niet eerder opkwam was omdat ik (naïef als ik ben) aannam dat het uitpakken van een array betekent dat dat dan ook gelijk voor de inhoud ervan zou gelden.

    rsluman op 30 januari 2015

    2. Het toekennen van een datatype op deze manier is niet heel netjes en wordt heel subtiel ‘bad programming style’ genoemd (heb ik ook niet bedacht).

    Ik deed dat voornamelijk omdat het zonder de „:Array” ertussen een foutmelding oplevert.

    rsluman op 30 januari 2015
     
    var inhoud = fileManager.contentsOfDirectoryAtURL(…) as? [NSURL]
     

    Dat wist ik niet dat op die manier kon. Goed om te weten, dat zal nog wel eens van pas komen vermoed ik.

    rsluman op 30 januari 2015

    In swift cast je door achter de variabelenaam ‘as’ te zetten, gevolgd door het gewenste datatype. De variabele waaraan je iets toewijst, krijgt dan automatisch dat datatype (wat in Swift ‘type inferring’ wordt genoemd).

    Ik ben bekend met casten:)

    rsluman op 30 januari 2015

    (Ik weet niet precies wat tekst voor object is, dus ik heb er maar even een UITextField van gemaakt, vandaar de .text-property.)

    Een NSTextView, en je had kunnen weten dat .text werkt, want zo staat het ook in mijn code;)

    rsluman op 30 januari 2015

    Hoop dat je hier iets aan hebt!

    Ja, zeker, dit verheldert nog meer.

    Wat ik wel nog altijd niet snap is waar die optionals nu precies goed voor zijn. Uit wat ik erover gelezen heb begrijp ik dat het concept vooral bedoeld is om te voorkomen dat er fouten optreden omdat een variabele nil is terwijl de programmeur daar geen rekening mee gehouden heeft, en Swift je daarom dwingt om ze bewust uit te pakken (middels !) zodat je wéét dat je daar om die „nil” heen moet programmeren. Maar voor zover ik kan zien leidt het vooral tot een hele berg code in de trant van

    if let uitvoer = item.absoluteString {
    	// Doe iets met uitvoer
    }

    waar je in sommige andere andere talen bijvoorbeeld

    if (uitvoer != nil) {
    	# Doe iets met uitvoer
    }

    zou gebruiken. Weinig verschil in de praktijk maar wel in het schrijven ervan omdat je op iets anders moeten letten dan anders … ?

8 berichten aan het bekijken - 1 tot 8 (van in totaal 8)

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