• Apfeltalk ändert einen Teil seiner Allgemeinen Geschäftsbedingungen (AGB), das Löschen von Useraccounts betreffend.
    Näheres könnt Ihr hier nachlesen: AGB-Änderung
  • Viele hassen ihn, manche schwören auf ihn, wir aber möchten unbedingt sehen, welche Bilder Ihr vor Eurem geistigen Auge bzw. vor der Linse Eures iPhone oder iPad sehen könnt, wenn Ihr dieses Wort hört oder lest. Macht mit und beteiligt Euch an unserem Frühjahrsputz ---> Klick

Anfänger on Tour - Erste App

SpecialFighter

Fießers Erstling
Registriert
25.04.12
Beiträge
131
Hallo alle zusammen,

seit knapp ner Woche beschäftige ich mit Xcode und Swift und bin dabei eine erst App zu "entwickeln"
Was das lernen angeht: Ich bevorzuge "learning by doing"

mir liegt es nicht so gut, iwelche Bücher zu lesen und die ganze theorie in meinen Kopf zu hämmern.
Aus Erfahrung bewährt sich bislang immer eine Resultat anzuschauen und daraus zu lernen.
Ich hoffe Ihr könnt mir auf diesem Wege helfen.

Jetzt zur eigentlichen Problematik.
Habe ein schönen Quellcode gefunden, der alle möglichen Barcodes scannen einlesen kann:

Code:
/*************** SCAN ***************/
    func StartScan() {
     
        // Button Scan ausblenden
        self.navigationItem.rightBarButtonItem = nil
     
        // Button Scan abbrechen einblenden
        self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Stop, target: self, action: "ScanAbbrechen")
        self.navigationItem.leftBarButtonItem!.tintColor = UIColor.whiteColor()

    
        self.highlightView.autoresizingMask = .FlexibleTopMargin | .FlexibleBottomMargin | .FlexibleLeftMargin | .FlexibleRightMargin
        self.highlightView.layer.borderColor = UIColor.greenColor().CGColor
        self.highlightView.layer.borderWidth = 3
        self.view.addSubview(self.highlightView)
     

        var error : NSError? = nil
        let input : AVCaptureDeviceInput? = AVCaptureDeviceInput.deviceInputWithDevice(device, error: &error) as? AVCaptureDeviceInput

        // Button ToogleLight einblenden falls vorhanden
        if (device.hasTorch) {
            var imageViewright:UIImageView = UIImageView()
            imageViewright.frame = CGRectMake(0, 0, 26, 26)
            var rightImage:UIImage = UIImage(named: "light")!
            imageViewright.image = rightImage
            var rightView:UIView = UIView()
            rightView.frame = CGRectMake(0, 0, 26, 26)
            rightView.addSubview(imageViewright)
            var rightGestureRecognizer:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "ToogleLight")
            rightView.addGestureRecognizer(rightGestureRecognizer)
            var rightItem:UIBarButtonItem = UIBarButtonItem()
            rightItem.customView = rightView
            self.navigationItem.rightBarButtonItem = rightItem
            rightItem.tintColor = UIColor.whiteColor()
        }
     
 
        if input != nil {
            session.addInput(input)
        }
     
        let output = AVCaptureMetadataOutput()
        output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
        session.addOutput(output)
        output.metadataObjectTypes = output.availableMetadataObjectTypes
     
     
        previewLayer = AVCaptureVideoPreviewLayer.layerWithSession(session) as! AVCaptureVideoPreviewLayer
        previewLayer.frame = self.view.bounds
        previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
        self.view.layer.addSublayer(previewLayer)
     
        session.startRunning()
}
 
 
/*************** BARCODE GEFUNDEN ***************/
    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
     
        var highlightViewRect = CGRectZero
        var barCodeObject : AVMetadataObject!
        var detectionString : String!

        let barCodeTypes = [
            AVMetadataObjectTypeUPCECode,
            AVMetadataObjectTypeCode39Code,
            AVMetadataObjectTypeCode39Mod43Code,
            AVMetadataObjectTypeEAN13Code,
            AVMetadataObjectTypeEAN8Code,
            AVMetadataObjectTypeCode93Code,
            AVMetadataObjectTypeCode128Code,
            AVMetadataObjectTypePDF417Code,
            AVMetadataObjectTypeQRCode,
            AVMetadataObjectTypeAztecCode,
            AVMetadataObjectTypeITF14Code,
            AVMetadataObjectTypeInterleaved2of5Code,
            AVMetadataObjectTypeFace,
            AVMetadataObjectTypeDataMatrixCode
        ]
     
 
        for metadata in metadataObjects {
            for barcodeType in barCodeTypes {
                if metadata.type == barcodeType {
                    barCodeObject = self.previewLayer.transformedMetadataObjectForMetadataObject(metadata as! AVMetadataMachineReadableCodeObject)
                    highlightViewRect = barCodeObject.bounds
                    detectionString = (metadata as! AVMetadataMachineReadableCodeObject).stringValue
                 
 
                 
                    self.session.stopRunning()
                    self.previewLayer.removeFromSuperlayer()
                 
                    if let oldInputs = self.previewLayer?.session.inputs{
                        for oldInput in oldInputs{
                            self.previewLayer?.session.removeInput(oldInput as! AVCaptureInput)
                        }
                    }
                 
                    if let oldOutputs = self.previewLayer?.session.outputs{
                        for oldOutputs in oldOutputs{
                            self.previewLayer?.session.removeOutput(oldOutputs as! AVCaptureOutput)
                        }
                    }


                    let newItem = NSEntityDescription.insertNewObjectForEntityForName("EAN_TEMP", inManagedObjectContext: self.managedObjectContext!) as! EAN_TEMP
                 
                    newItem.eancode = "\(detectionString)"
                    println ("\(detectionString)")
       
                 
                    performSegueWithIdentifier("goToNextViewer", sender: nil)

                    break
                }
            }
        }
    }

Allerdings ist mir aufgelanne (was auf der eine Seite eigentlich ganz witzig ist, aber auch unschön) dass wenn man anstatt über einen Barcode, über ein Gesicht mit der Kamera geht, stürzt die App ab.

2015-06-01 07:54:46 +0000
Could not cast value of type 'AVMetadataFaceObject' (0x197b606a0) to 'AVMetadataMachineReadableCodeObject' (0x197b60740).
(lldb)

Könnte mir jemand verraten was das beudetet?

*UPDATE*
Habe den Fehler gefunden. Hatt unter BarCodeTypes
AVMetadataObjectTypeFace drin ...
 
Zuletzt bearbeitet:

m1LLo

Osnabrücker Reinette
Registriert
29.05.10
Beiträge
991
Naja weist du was ein Cast ist? dann sollte sich die Fehlermeldung selbst erklären.
 

SpecialFighter

Fießers Erstling
Registriert
25.04.12
Beiträge
131
Aber trotzdem für mein Verständnis. Nein ich weiß nicht was ein Cast ist.
Könntest du mir dies bitte erklären? :)
 

m1LLo

Osnabrücker Reinette
Registriert
29.05.10
Beiträge
991
Ein Cast ist eine Umwandlung von einem "Datentyp/Objekttyp" in einen anderen. Für einfache Datentypen ist das ziemlich simple. Eine Fließkommazahl in eine Integerzahl zu verwandeln ist für jeden noch logisch und einfach. Bei komplexeren Objekten ist es nicht so einfach möglich und es muss festgelegt werden wie das passieren soll. Oder wie würdest du eine Umwandlung von einem Apfel-Objekt und ein Birnen-Objekt machen?
 

SpecialFighter

Fießers Erstling
Registriert
25.04.12
Beiträge
131
Sehr gute Erklärung - vielen Dank dafür :)

Weitere Frage - habe noch mehr davon :)
korrigiert mich bitte, wenn ich etwas falsch gemacht habe bzw. wenn es besser geht.

habe einen ViewController A mit Navigation Controller und einen weiteren ViewController B

ViewController A = ViewControllerA.swift
ViewController B = ViewControllerB.swift

im VC A kann ich den o.g. Barcode scannen und dieser wird in einer variable innerhalber func gespeichert.
diesen Wert möchte ich gerne an den VC B übergeben - das habe ich einfach nicht hinbekommen.

aktuell habe ich mir ganz "elegant" ausgeholfen:

der BarCode wird im VC A mit Hilfe von Core Date gespeichert
VC B ruft diesen dann ab

- Schön ist wahrscheinlich anders -

Könnt Ihr mir dabei helfen?
Wenn Ihr iwas braucht - sagt mir bitte was
 

Buhmi

Osnabrücker Reinette
Registriert
21.11.09
Beiträge
977
Du könntest beim Wechsel von A zu B im Segue den gefundenen Wert mit übergeben. Das müsste in der prepareForSegue Methode möglich sein. Gib Controller B ein property im Header und setze dieses in prepareForSegue auf den erkannten Wert. Bin leider nicht so fit in Swift, dass ich das hier runtertippen kann, aber so in die Richtung. Core Data ist auf jeden Fall mit Kanonen auf Spatzen schießen :)
 

SpecialFighter

Fießers Erstling
Registriert
25.04.12
Beiträge
131
Mit Kanonen auf Spatzen schießen - den kannt ich auch noch nicht :eek:
Aber ich würde auch treffen ;)


Aber vielen Dank für deinen Tipp.
Habe ich jetzt so gelöst und klappt super:

Code:
/*************** EAN Code -> NextController ***************/
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "goToNextViewer" {
            if let destinationVC = segue.destinationViewController as? NextController{
                destinationVC.eancode = self.detectionString
            }
        }
    }


eine weitere Frage:
in meiner App kann man mehrere Datierungen (hoffe das ist der Plural von Datum) eintragen.

Beispiel:
- 05.06.2015
- 28.09.2015

jetzt möchte ich das beim "speichern" des jeweiligen Datums (omg ich hasse dieses Wort)
eine locale notification "registriert" wird, welche 2 tage vor dem eingetragenen Datum erscheinen soll?


eine locale notification habe ich mit diesem Code gelöst:

Code:
        var localNotification = UILocalNotification()
        localNotification.fireDate = NSDate(timeIntervalSinceNow: 5)
        localNotification.alertBody = "Neue Nachricht von meiner App"
        localNotification.timeZone = NSTimeZone.defaultTimeZone()
        localNotification.applicationIconBadgeNumber = UIApplication.sharedApplication().applicationIconBadgeNumber + 1
        UIApplication.sharedApplication().scheduleLocalNotification(localNotification)

Diese Zeile bedeutet für mich, dass die Nachricht 5 sek nach App start erscheinen soll, oder?
localNotification.fireDate = NSDate(timeIntervalSinceNow: 5)

wie müsste ich diese Zeile anpassen, damit mein o.g. Wunsch realisiert werden kann.
Noch eine Frage zum Verständnis:
was passiert wenn das iphone Mal aus war und die App danach nicht mehr gestartet wurde.
erscheinen dann trotzdem die locale notifications?
 
Zuletzt bearbeitet:

Buhmi

Osnabrücker Reinette
Registriert
21.11.09
Beiträge
977
Lokale Notifications werden vom System behandelt. Die App beauftragt das System mit der Ausführung der Notification zum angegeben Zeitpunkt. In deinem Beispiel liegt dieser allerdings 5 Sekunden in der Zukunft, die Chance, dass diese Benachrichtigung korrekt ausgeführt wird ist also ziemlich gering. Zumal sich der User mit großer Wahrscheinlichkeit immer noch in der App selbst befindet und deshalb die Notification nicht per Balken etc. angezeigt wird.

Möchtest du eine Notification zu einem bestimmten NSDate ausführen, musst du dieses Date einfach als fireDate setzen. Du musst also irgendwie das gewünschte Datum in Form eines NSDates bis zum planen der UILocalNotification bekommen :)

Edit: Aus- und Einschalten stört natürlich auch nicht, da das System sich selbst um die Notifications kümmert. Unabhängig vom Zustand der App. Im Detail ist das übrigens alles hier erklärt: https://developer.apple.com/library/ios/documentation/iPhone/Reference/UILocalNotification_Class/
 

SpecialFighter

Fießers Erstling
Registriert
25.04.12
Beiträge
131
Verstehe ich es dann richtig, dass die Notifications dann trotzdem angezeigt werden, wenn das iphone mal aus war und die app nicht gestartet wurde, da diese Info im System hinterlegt ist?

gibt es keine Möglichkeit das firedate anhan eines festen Datums zu setzen?

Beispiel:

eingetragen wird 05.06.2015
dann soll als firedate 03.06.2015 eingesetzt werden
 

Buhmi

Osnabrücker Reinette
Registriert
21.11.09
Beiträge
977
Ja das verstehst du richtig. Und du kannst ein beliebiges festes Datum setzen. Setze einfach statt NSDate(timeIntervalSinceNow: 5) ein NSDate Objekt mit deinem gewünschten Datum. Mal als Beispiel mit einem NSDateFormatter:

Code:
// Date aus vorhandenem String parsen
let dateAsString = "03.06.2015"
let formatter = NSDateFormatter.new()
formatter.dateFormat = "dd.MM.yyyy"
let date = formatter.dateFromString(dateAsString)

// Notification mit gefundenem Date erstellen
var localNotification = UILocalNotification()
localNotification.fireDate = date
localNotification.alertBody = "Neue Nachricht von meiner App"
localNotification.timeZone = NSTimeZone.defaultTimeZone()
localNotification.applicationIconBadgeNumber = UIApplication.sharedApplication().applicationIconBadgeNumber + 1
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
 

SpecialFighter

Fießers Erstling
Registriert
25.04.12
Beiträge
131
Ja das verstehst du richtig. Und du kannst ein beliebiges festes Datum setzen. Setze einfach statt NSDate(timeIntervalSinceNow: 5) ein NSDate Objekt mit deinem gewünschten Datum. Mal als Beispiel mit einem NSDateFormatter:

Code:
// Date aus vorhandenem String parsen
let dateAsString = "03.06.2015"
let formatter = NSDateFormatter.new()
formatter.dateFormat = "dd.MM.yyyy"
let date = formatter.dateFromString(dateAsString)

// Notification mit gefundenem Date erstellen
var localNotification = UILocalNotification()
localNotification.fireDate = date
localNotification.alertBody = "Neue Nachricht von meiner App"
localNotification.timeZone = NSTimeZone.defaultTimeZone()
localNotification.applicationIconBadgeNumber = UIApplication.sharedApplication().applicationIconBadgeNumber + 1
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)


habe mir mal date als println ausgeben lassen:
Optional(2015-06-02 22:00:00 +0000)

iwas stimmt da doch nicht oder?
müsste doch lauten:

Optional(2015-06-03 22:00:00 +0000)
gibt es auch noch ne Möglichkeit, die Uhrzeit auf 00:00:00 zu setzen?
 

MacApple

Schöner von Bath
Registriert
05.01.04
Beiträge
3.652
habe mir mal date als println ausgeben lassen:
Optional(2015-06-02 22:00:00 +0000)

iwas stimmt da doch nicht oder?
müsste doch lauten:

Optional(2015-06-03 22:00:00 +0000)
Da ist alles korrekt. NSDateFormatter beachtet die eingestellte Zeitzone, println tut das nicht. NSDate speichert intern die Zeit immer als UTC Zeit. Da dein Rechner offensichtlich auf deutsche Sommerzeit eingestellt ist, entspricht 03.06.2015 0:00 Uhr der UTC Zeit 02.06.2015 22:00 Uhr. Wenn du die Zeit wieder ausgeben willst, musst du die Zeitzone berücksichtigen, also wieder über den NSDateFormatter in einen String umwandeln.

gibt es auch noch ne Möglichkeit, die Uhrzeit auf 00:00:00 zu setzen?
Es ist ja 0:00 Uhr, nur halt deutsche Sommerzeit und nicht UTC.