Vai al contenuto


Lief

Come si usa C in Swift? Progetto esempio

Recommended Posts

Ieri notte ero particolarmente creativo e ho ricevuto l'illuminazione per la creazione di un piccolo programma che rinomina i file in batch in modo progressivo (esempio prendo 10 file li rinomina da 000 a 009).

Ma quale linguaggio usare?

Ho pensato subito al C perchè è ottimo per prototipizzare sui file (è un linguaggio molto semplice che, senza librerie aggiuntive, consente di usare semplici system call come rename o chiamare la bash con system), anche se successivamente mi sono quasi pentito della scelta (visto e considerato come si lavora male sulle stringhe).

Dopo averlo creato (come vedete molto velocemente, usando addirittura un goto per puro sfizio di farlo):

Spoiler
//
//  main.c
//  RinominaFast
//
//  Created by LiefLayer on 06/07/17.
//  Copyright © 2017 LiefLayer. All rights reserved.
//

#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int argc, const char * argv[]) {
    char stringa[256];
    char stringaFinal[256][256];
    int ret = -1;
    char oldname[256][256];
    char oldnameWithEstension[256][256];
    char path[256];
    int index = 0;
    char myInt[3];
    char myEstension[5];
    int numElem = 0;
    
    //immetto i nomi dei file da rinominare
start:
    printf("Immetti il nome del file attuale con l'estensione, digitare stop per fermarsi!\n");
    if (fgets(oldname[index], sizeof(oldname[index]), stdin)) {
        if (oldname[index][strlen(oldname[index]) - 1] == '\n') {
            oldname[index][strlen(oldname[index]) -1] = '\0';
        }
        if(strcmp(oldname[index], "stop") != 0){
            index++;
            goto start;
        }else{
            oldname[index][0] = '\0';
            index--;
            numElem = index;
        }
    }else {
        printf("Errore 00: nome attuale troppo lungo\n");
    }
    
    index = 0;
    //immetto il path dei file da rinominare
    printf("Immetti il path del file attuale!\n");
    if (fgets(path, sizeof(path), stdin)) {
        if (path[strlen(path) - 1] == '\n') {
            path[strlen(path) -1] = '\0';
        }
    }else {
        printf("Errore 02: path troppo lungo\n");
    }
    
    while(index <= numElem){
        strcat(stringaFinal[index], path);
        index++;
    }
    
    index = 0;
    
    //prendo il nuovo nome del file
    printf("Immetti il nome principale!\n");
    if (fgets(stringa, sizeof(stringa), stdin)) {
        if (stringa[strlen(stringa) - 1] == '\n') {
            stringa[strlen(stringa) -1] = '\0';
        }
    }else {
        printf("Errore 01: nome troppo lungo\n");
    }
    
    while(index <= numElem){
        strcat(stringaFinal[index], stringa);
        index++;
    }
    
    index = 0;
    
    while(index <= numElem){
        //imposto l'index da intero a stringa
        sprintf(myInt, "%d", index);
        if(index > 9){
            strcat(stringaFinal[index], "0");
        }else{
            strcat(stringaFinal[index], "00");
        }
        //lo metto nel mio nome finale insieme al giusto numero di zeri
        strcat(stringaFinal[index], myInt);
        index++;
    }
    
    index = 0;
    
    
    //aggiungo l'estensione
    printf("Immetti l'estensione!\n");
    if (fgets(myEstension, sizeof(myEstension), stdin)) {
        if (myEstension[strlen(myEstension) - 1] == '\n') {
            myEstension[strlen(myEstension) -1] = '\0';
        }
    }else {
        printf("Errore 03: estensione errata\n");
    }
    
    while(index <= numElem){
        strcat(stringaFinal[index], myEstension);
        index++;
    }
    
    index = 0;
    
    while (index <= numElem) {
        strcat(oldnameWithEstension[index], path);
        strcat(oldnameWithEstension[index], oldname[index]);
        //rinomino il mio vecchio file con il nuovo nome compreso di estensione
        ret = rename(oldnameWithEstension[index], stringaFinal[index]);
        
        if(ret == 0){
            printf("Successo File %d %s %s %s!\n", index, oldname[index], oldnameWithEstension[index], stringaFinal[index]);
        }else{
            printf("Fallimento File %d!\n", index);
        }
        index++;
        

    }
    
    
    printf("Fine!\n");
    return 0;
}

 

 

Ho pensato che fosse un'ottima scusa per provare a utilizzare tale codice dentro un'applicazione con solo l'interfaccia grafica scritta in Swift.

 

Per farlo ho trovato molto pi√Ļ rapido incapsulare il mio codice C dentro una classe Objective-C (√® stato cos√¨ molto pi√Ļ semplice passare le stringhe come parametri):

Spoiler
//
//  Core.m
//  RinominaFast
//
//  Created by LiefLayer on 06/07/17.
//  Copyright © 2017 LiefLayer. All rights reserved.
//

#import <Foundation/Foundation.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#import "Core.h"

@implementation Core

char stringa[10000];
char stringaFinal[10000][10000];
char oldname[10000][10000];
char oldnameWithEstension[10000][10000];
char path[10000];
int myIndex = 0;
char myInt[10000];
char myEstension[1000];
int numElem = 0;
char commando[10000];

//immetto i nomi dei file da rinominare
- (int) coreProgramPart1 : (NSString *) daRinominare{
    strcpy(oldname[myIndex], [daRinominare UTF8String]);
    if (oldname[myIndex][strlen(oldname[myIndex]) - 1] == '\n') {
        oldname[myIndex][strlen(oldname[myIndex]) -1] = '\0';
    }
    if(strcmp(oldname[myIndex], "stop") != 0){
        myIndex++;
        return 1;
    }else{
        oldname[myIndex][0] = '\0';
        myIndex--;
        numElem = myIndex;
    }
    
    myIndex = 0;
    
    return 0;
}

- (void) coreProgramPart0 : (NSString *) daRinominare{
    strcpy(path, [daRinominare UTF8String]);
    if (path[strlen(path) - 1] == '\n') {
        path[strlen(path) -1] = '\0';
    }
    
    while(myIndex <= numElem){
        strcpy(stringaFinal[myIndex], "");
        strcat(stringaFinal[myIndex], path);
        myIndex++;
    }
    
    myIndex = 0;
}

- (void) coreProgramPart2 : (NSString *) daRinominare{
    strcpy(stringa, [daRinominare UTF8String]);
    if (stringa[strlen(stringa) - 1] == '\n') {
        stringa[strlen(stringa) -1] = '\0';
    }
    
    while(myIndex <= numElem){
        strcat(stringaFinal[myIndex], stringa);
        myIndex++;
    }
    
    myIndex = 0;
}

- (void) coreProgram {
    while(myIndex <= numElem){
        //imposto l'index da intero a stringa
        sprintf(myInt, "%d", myIndex);
        if(myIndex > 9 && myIndex <= 99){
            strcat(stringaFinal[myIndex], "0");
        }else if(myIndex > 99){
            strcat(stringaFinal[myIndex], "");
        }else{
            strcat(stringaFinal[myIndex], "00");
        }
        
        //lo metto nel mio nome finale insieme al giusto numero di zeri
        strcat(stringaFinal[myIndex], myInt);
        myIndex++;
    }
    
    myIndex = 0;
    
}

- (void) coreProgramPart3 : (NSString *) daRinominare{
    strcpy(myEstension, [daRinominare UTF8String]);

    //aggiungo l'estensione
    if (myEstension[strlen(myEstension) - 1] == '\n') {
        myEstension[strlen(myEstension) -1] = '\0';
    }
    
    while(myIndex <= numElem){
        strcat(stringaFinal[myIndex], myEstension);
        myIndex++;
    }
    
    myIndex = 0;
    
    //costruisce e passa il comando da eseguire su bash
    while (myIndex <= numElem) {
        strcat(oldnameWithEstension[myIndex], path);
        strcat(oldnameWithEstension[myIndex], oldname[myIndex]);
        //rinomino il mio vecchio file con il nuovo nome compreso di estensione
        int ret = rename(oldnameWithEstension[myIndex], stringaFinal[myIndex]);
        
        if(ret == 0){
            printf("Successo File %d \n", myIndex);
        }else{
            printf("Fallimento File %d \n", myIndex);
        }
        
        myIndex++;
        
    }
    myIndex = 0;
    
    while (myIndex <= numElem) {
        strcpy(oldnameWithEstension[myIndex], "");
        strcpy(stringaFinal[myIndex], "");
        strcpy(oldname[myIndex], "");
        myIndex++;
    }
    myIndex = 0;
    
    
    
    printf("Fine!\n");
}


@end

 

 

Ovviamente questo è il codice finale, in mezzo ci sono stati tanti passaggi.

 

Ho così creato il .h per questa classe

Spoiler
//
//  Core.h
//  RinominaFast
//
//  Created by LiefLayer on 06/07/17.
//  Copyright © 2017 LiefLayer. All rights reserved.
//

#ifndef Core_h
#define Core_h

#import <Foundation/Foundation.h>

@interface Core : NSObject

- (int) coreProgramPart1: (NSString *) daRinominare;

- (void) coreProgramPart0: (NSString *) daRinominare;

- (void) coreProgramPart2: (NSString *) daRinominare;

- (void) coreProgram;

- (void) coreProgramPart3: (NSString *) daRinominare;

@end

#endif /* Core_h */

 

e come si può vedere non ho dovuto modificare praticamente nulla del mio codice C vero e proprio.

Ho dovuto infatti solo aggiungere il wrapper della classe e dei metodi Objective-C.

Ovviamente ho dovuto anche creare un piccolo file bridge

NomeProgetto-Bridging-Header.h

dove ho solo scritto

#import "Core.h"

Successivamente ho poi modificato il codice per adattarsi alla mia interfaccia grafica scritta in Swift (che ovviamente prevede la selezione dei file attraverso una finestra di selezione dei file):

Spoiler
//
//  ViewController.swift
//  RinominaFast
//
//  Created by LiefLayer on 06/07/17.
//  Copyright © 2017 LiefLayer. All rights reserved.
//

import Cocoa

class ViewController: NSViewController {

    var instanceOfCore: Core = Core()
    var retPart1: Int = -1
    var daRinominare: String! = "";

    @IBOutlet var stringInInput: NSTextField!
    
    @IBOutlet var filename_field: NSTextField!
    
    var path = ""
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }
    
    @IBAction func browseFile(_ sender: Any) {
        
        let dialog = NSOpenPanel();
        
        dialog.title                   = "Choose files";
        dialog.showsResizeIndicator    = true;
        dialog.showsHiddenFiles        = false;
        dialog.canChooseDirectories    = true;
        dialog.canCreateDirectories    = true;
        dialog.allowsMultipleSelection = true;
        
        if (dialog.runModal() == NSModalResponseOK) {
            let result = dialog.urls // Pathname of the file
            var pathMyFile = ""
            var toIndex = 0;
            path = ""
            filename_field.stringValue = ""
            
            
            while(toIndex < result.count){
                path = result[toIndex].path
                filename_field.stringValue = filename_field.stringValue + path + "'"
                let myUrl = URL(fileURLWithPath: path)
                let dirUrl = myUrl.deletingLastPathComponent()
                pathMyFile = dirUrl.path + "/"
                path = result[toIndex].lastPathComponent
                retPart1 = Int(instanceOfCore.coreProgramPart1(path));
                path = result[toIndex].pathExtension
                toIndex += 1;
            }
            retPart1 = Int(instanceOfCore.coreProgramPart1("stop"));
            instanceOfCore.coreProgramPart0(pathMyFile)
            
        } else {
            // User clicked on "Cancel"
            return
        }
        
    }

    @IBAction func launchPart2(_ sender: Any) {
        if(retPart1 != 0){
            return;
        }
        daRinominare = stringInInput.stringValue
        instanceOfCore.coreProgramPart2(daRinominare)
        instanceOfCore.coreProgram();
        instanceOfCore.coreProgramPart3("."+path)
    }

}

 

 

 

Ovviamente il programma non è per nulla ottimizzato e potrebbe avere dei bug (non mi prendo responsabilità in caso perdiate dei dati, quindi non utilizzate questo programma su dati importanti).

Però l'obbiettivo primario è stato raggiunto.

Il programma è attualmente una sorta di MVC in cui la View (l'interfaccia grafica) è scritta in Swift e non ha alcuna funzionalità se non quella di passare l'input al Model (la classe C wrappata all'interno dell'Objective-C) attraverso il Controller (il bridge).

Tutte le funzionalità di base sono svolte backend dal codice C originale, solo l'interfaccia grafica è in Swift.

 

Questo mini-tutorial si conclude qui, spero che sia stato utile a qualcuno.

Se volete pi√Ļ informazioni vi consiglio questo link stackoverflow:

Concludo dicendo solo che per usare le funzioni C in Swift direttamente (senza Objective-C) si può fare in questo modo:

funzione_c("World".cStringUsingEncoding(NSUTF8StringEncoding))

lo scrivo perchè in linea di massima è l'unica cosa non proprio intuitiva ("come usare un oggetto C se in C gli oggetti non esistono? Semplice ne hanno creato uno").

 

Il vantaggio principale è ovviamente che se avete del codice C, C++ o Objective-C già scritto.... Oppure vi piace scrivere in linguaggi diversi. Potete farlo.

In linea di massima potreste persino non saper scrivere codice Swift (e la costruzione dell'interfaccia grafica è particolarmente semplice).

Modificato da Lief

Condividi questo messaggio


Link di questo messaggio
Condividi su altri siti


Crea un account o accedi per lasciare un commento

You need to be a member in order to leave a comment

Crea un account

Iscriviti alla nostra comunit√†. √ą facile!

Crea un nuovo account

Accedi

Sei già iscritto? Accedi qui.

Accedi Ora

  • Contenuti simili

    • Da Bacchinif
      Salve, forum di Italiamac! Questa sezione, cos√¨ come altre del forum, purtroppo sta un po' morendo ed ho cos√¨ deciso di postare una guida all'acquisto per terminali tra i 180‚ā¨ ed i 280‚ā¨ che stesso io ho redatto su un altro forum di settore. Mi sono, quindi, preso la brida di fare un crossposting da quel forum a questo essendo io l'autore del thread originario.¬†
      Buona lettura a tutti :).
       
      Salve a tutti, qualche settimana fa avevo gi√† postato nella sezione dedicata al confronto tra i terminali al di sotto dei 215‚ā¨, senza, per√≤, avere grosse risposte in merito. Mi sono, cos√¨, armato di pazienza ed ho redatto una lista di tutti gli smartphone che soddisfino una serie precisa di caratteristiche:
       
      Banda 20¬†(escludiamo smartphone destinati non ai nostri mercati) Aggiornabile ad Oreo 8.0¬†(o versioni successive, indipendentemente se stock o meno) Prezzo: 180‚ā¨ - 300‚ā¨¬†(includendo tutti gli store, rinunciando anche alla garanzia italiana se necessario) Altezza Limite 160 mm¬†-¬†EDIT:¬†L'intento del thread era quello di trovare i migliori telefoni compatti, ma, poi, mi sono reso conto che davvero non c'√® partita e che ormai bisogna per forza acquistare un "Phablet" per portarsi a casa qualcosa di quantomeno decente. L'era dei telefoni fino a 150 mm √® terminata, a meno di non andare su top di gamma costosissimi. Uscito Massimo da 7 Mesi¬†(ci√≤ garantirebbe maggior longevit√†, a discapito di fenomeni come l'obsolescenza programmata)


      IMPORTANTE:¬†Dalla lista escludo anche tutti gli smartphone top di gamma 2016-2017 (pur rientranti nelle categorie succitate) semplicemente allo scopo di poter avere un prodotto nuovo sia dal punto di vista estetico che anagrafico. Esempio: √® probabile che un¬†Samsung Galaxy S6¬†sia superiore ad uno o pi√Ļ dei telefoni presenti in questa lista, ma senza dubbio √® passi indietro dal punto di vista del design (non segue il fenomeno borderless o del 18:9), software (fermo a Nougat, se non erro) o fotografico (per quanto faccia buone foto, segue "schemi vecchi", senza l'ausilio di dual cam o di software con effetto bokeh e simili).

      Bene, a fronte di tutto ciò, per ogni smartphone ho deciso di prendere in considerazione una serie di parametri, quali:
       
      Materiali
      Design
      Altezza
      Larghezza
      Fingerprint (Posizionamento)
      Dimensioni Display
      Aspect Ratio
      Risoluzione Display
      Frequenza Aggiornamenti e Sicurezz
      Storage
      RAM
      CPU
      GPU
      Batteria
      Data di Rilascio
      Benchmark AnTutu
      Jack 3.5
      Tipo C
      Connettività (Bluetooth e Wi-Fi)

      Ad ognuno di questi parametri ho affidato un punteggio da 0 a 5, includendo anche gli eventuali decimali e, quindi, (pur ammesso che la valutazione del design è soggettiva, così come il punteggio attribuito alla voce "dimensioni display") facendo una somma di tutti i punteggi si dovrebbe arrivare ad uno score finale "oggettivo".
      Ribadisco, nuovamente, che questa classifica √®¬†PERSONALE¬†ed in quanto tale va presa con le pinze. Di fatti i punteggi dati sono spesso soggettivi e sulla base di alcune preferenze che possono variare da utente ad utente. Nel mio caso, ad esempio, reputo ideale un dispositivo con una diagonale di 5,5''-5,7'', ma che non superi i 150 mm di altezza. Contrariamente qualcuno potrebbe volere un display pi√Ļ piccolo e contestualmente un dispositivo dalle dimensioni pi√Ļ ridotte. Analogamente, io reputo scomodo il sensore biometrico frontale, quindi a questo parametro ho dato un valore basso.

      ATTENZIONE: Nel computo totale non sono incluse voci o riferimenti alla fotocamera, per la quale, purtroppo, ci vuole un post dedicato a parte in quanto non è valutabile tramite dati oggettivi (megapixel, sensore, dimensione pixel, software utilizzato e così via), bensì su parametri "fenomenologici" (confronto diretto delle immagini in varie condizioni di luce). 

      LEGENDA

      * In¬†grassetto-blu¬†ho contrassegnato tutti quei punteggi che derivano da un giudizio personale che, quindi, pu√≤ variare da utente ad utente. Nel caso non siate concordi con la mia valutazione, attribuite voi un voto e ricalcolate il totale. Questa √® una operazione importante da fare perch√© il totale che ne esce fuori √® pesantemente influenzato da tali fattori, ad esempio: lo Xiaomi Redmi Note 5 ha un valore complessivamente pi√Ļ basso di altri terminali presenti in questa categoria solo perch√©, dal mio punto di vista, √® troppo grande, di scarsa fattura (materiali scadenti, facilmente usurabili) e dal design poco originale (praticamente uguale a quasi tutti gli Xiaomi da tre anni a questa parte).

      * La dicitura prezzo minimo si riferisce al prezzo minimo mai registrato, facendo una interpolazione tra tutte le piattaforme. La consultazione l'ho fatta facendo ricerche su noti siti di e-commerce o su vari motori di ricerca (TrovaPrezzi e Kimovil).

      * I Pro ed i Contro, ancora una volta, sono semplicemente un "riassunto" a parole di quanto si evince già nei voti. Molti dei pro e dei contro inseriti sono puramente personali, quindi prendeteli con le pinze.

      * Per ogni dispositivo viene riportata la configurazione massima, quindi quella con il maggior numero di RAM e Spazio di Archiviazione. In fase di acquisto fate attenzione a prendere quella se necessario.

      Iniziamo...!

      ATTENZIONE: I prezzi riportati sono quelli di maggio 2018, ma con il passare dei mesi direi che si sono tutti pi√Ļ o meno abbassati. Esempio: Sony Xperia XA2 prezzato di media sui 270‚ā¨ al Prime Day costava 220‚ā¨. Stesso ragionamento per altri terminali qui sotto che sono scesi anche al di sotto della soglia di questo thread, come Honor 9 Lite che √® arrivato a 160‚ā¨ sempre al Prime Day.¬†
      Per i prezzi vedetevela voi. Qui non voglio segnalare le migliori offerte, ma lo scopo è semplicemente quello di attribuire ad ogni smartphone un punteggio complessivo ESCLUDENDOi fattori multimediali:

      - Comparto Audio
      - Comparto Fotografico

      che non sarei in grado di valutare a distanza, non avendo provato i terminali di persona.
       
    • Da Stef6Gor
      Salve,
      Sono in procinto di acquistare una nuova tavoletta grafica, puntando a spendere il meno possibile.
      Ero indeciso tra la molto conveniente huion h420 a 30 euro, la 420 a 20 oppure puntare ad una xp pen deco 01 a 60 euro.
      Ho utilizzato una tavoletta grafica, ma l'ho tenuta per poco tempo, poiché era in prestito (wacom intuos draw). Ho visto delle recensioni e tutte dicono che la deco 01 sia una bomba come tavoletta, ma sono veramente indeciso, in quanto ha un costo non bassissimo (per il mio portafogli).
      La huion h420/420 costa 20/30 euro, ma mi sembra veramente minuscola come tavoletta.
      Ci potrebbero essere eventuali alternative con area attiva abbastanza grande intorno ai 40 euro?
    • Da cianfiosti
      Ciao a tutti,
      un tutorial su Indesign per esportare in modo corretto i PDF per la stampa.
       
      niccolò
       

       
      http://www.progettoimmagina.com/esportare-pdf-per-la-stampa-tutorial/
  • Statistiche forum

    529119
    Discussioni Totali
    6333425
    Risposte Totali
  • Statistiche Utenti

    122114
    Utenti totali
    14120
    Record utenti online
    Riccardo Petrucci
    Nuovo iscritto
    Riccardo Petrucci
    Iscritto
  • Statistiche annunci

    119
    Annunci attivi
    18
    Domande
    0
    Recensioni
    0
    Offerte
    Ultimi Annunci
    By angillo
    29 giorni e 13 ore
√ó