Code Snippets

Einige gesammelte Code Schnipsel und Codezeilen z.B. Shell-Scripte, Objective-C, oder Ähnliches.

Shell: Reset des USB-Subsystems

Ist mir persönlich jetzt schon mehrfach passiert, das das USB-Subsystem nicht mehr funktioniert hat. Sprich, bestimmte Festplatten wurden nicht mehr registriert beim einstecken oder bestimmte Smartphones. Man kann jedoch im Betrieb das USB zurücksetzen. Ein wenig Vorsicht ist aber geboten… denn die Tastatur und Maus hängt auch am USB wie der Teilweise berichtet. Wenn man das also runterfährt kann man seine Maschine nicht mehr steuern.

Man kann dennoch einfach die USB-Kernelextension ausknipsen und wieder an. Am besten startet man das Anschalten automatisch nach paar Sekunden, dann muss man sich nicht mühevoll auf die eigene Kiste einloggen. Ich hab die Codezeilen vom Teilweise mal etwas gepimp’ed. (bash-Script als restartSubsystemUsb.txt laden).

#!/bin/sh
#
# Script to restart the USB subsystem by unloading and reloading the
# USB kernel extension which drives the USB system components.
# This is useful if you have unresponding USB ports or devices
# which are no longer correctly registered in the USB system
# after some weird errors happened and you don't feel like restating
# your whole machine just for this to be fixed.
#
if (( $EUID != 0 )); then
	echo "PLEASE RUN AS ROOT."
	exit
fi

echo ""
echo "RESTARTING USB SUBSYSTEM NOW..."
sleep 2
echo "SHUTDOWN..."
sleep 2
# shutting down here
echo "TIME: `date`"
kextunload -b com.apple.driver.AppleUSBEHCI
echo "TIME: `date`"
echo "WAITING 20 SECONDS..."
sleep 20
echo "RESTART..."
# rebooting here
echo "TIME: `date`"
kextload -b com.apple.driver.AppleUSBEHCI
echo "TIME: `date`"
echo "DONE"
echo ""

Man bekommt dann ungefähr sowas hier als Output, während alle Geräte, auch die Bluetoothgeräte (wie Trackpad) kurzzeitig ihre Verbindung verlieren.


RESTARTING USB SUBSYSTEM NOW...
SHUTDOWN...
TIME: Di 16 Sep 2014 10:52:19 CEST
(kernel) Can't unload kext com.apple.driver.AppleUSBEHCI; classes have instances:
(kernel) Kext com.apple.driver.AppleUSBEHCI class AppleEHCIIsochTransferDescriptor has 168 instances.
(kernel) Kext com.apple.driver.AppleUSBEHCI class AppleEHCIIsochEndpoint has 5 instances.
Failed to unload com.apple.driver.AppleUSBEHCI - (libkern/kext) kext is in use or retained (cannot unload).
TIME: Di 16 Sep 2014 10:52:20 CEST
WAITING 20 SECONDS...
RESTART...
TIME: Di 16 Sep 2014 10:52:40 CEST
TIME: Di 16 Sep 2014 10:52:40 CEST
DONE

Objective-C: iOS 7/iOS 8 Transition von iOS 6

Th best 2 lines of code for the transition you will ever find:

myViewController.edgesForExtendedLayout = UIRectEdgeNone;
rootNavigationController.navigationBar.translucent = NO;
rootNavigationController.toolbar.translucent = NO;

Shell: Inkompatibilitäten von Steuercodes für Cursortasten in vi abstellen

Wenn man sich per ssh auf andere Machinen einloggt, und per vi doch mal was editieren will, hat man oftmals das Problem, dass die Steuersequenzbelegung der Cursortasten von der eigene Emulation mal wieder nicht kompatibel ist. Folge ist z.B. bei vi gerne mal, dass man im edit-mode bei Nutzung der Cursortasten dann A, B, C, D erzeugt und der Cursor wegspringt. Auch das Löschen mit Backspace funktioniert nicht richtig. Das kann man schnell beheben indem man im vi zuerst eingibt:

:set nocompatible

Oder aber man legt folgende Konfigurationsdatei für vi/vim im $HOME an:

.vimrc

mit dem folgenden Inhalt (man beachte wie ähnlich das zur Eingabe im vi ist):

set nocompatible

Das setzt einen Parameter bei jedem Start von vi. So wird das problem jedoch nur für den vi gelöst. Andere Kommandozeilentools leiden weiterhin. Deshalb alternativ kann man auch in dem eigenen Terminal Programm mal in den Settings wühlen und die default-Emulation mal ändern (da stehen oft so Sachen wie xterm-color16, ansi, vt100, linus, usw.). Sofern „linux“ verfügbar ist sollte man das mal nehmen. Wird aber meist erst aktiv nach einem Neustart des eingesetzten Terminal Programms.

Shell: Text to PDF von der Kommandozeile

Hiermit kann man von der Kommandozeile aus normalen Text in schön formatiertes PDF umleiten, mittels enscript, das man widerum per MacPorts installieren kann.

#!/bin/bash

MOD_TIME_EPOCH=`stat -f %m $1`
MOD_TIME_FMT=`date -r $MOD_TIME_EPOCH +'%a %e %b %Y @ %R %Z' | sed 's/ [ ]*/ /g'`
FULL_NAME=`php -r "echo realpath('$1');"`

mkdir -p $HOME/.enscript

# Create temporary "fancy header" file for enscript.
cat > $HOME/.enscript/tmp_txt2pdf.hdr <<EOF
% -- code follows this line --
%Format: last_mod_timestr $MOD_TIME_FMT
%Format: pagestr page \$V$%/$=
%HeaderHeight: 30
%FooterHeight: 30
/Helvetica /helvetica-encoded MF
/Helvetica-10-Regular /helvetica-encoded findfont 10 scalefont def
/Helvetica-Bold /helvetica-bold-encoded MF
/Helvetica-10-Bold   /helvetica-bold-encoded findfont 10 scalefont def
/new_marg 4 def
/do_header {
  gsave
    Helvetica-10-Bold setfont
    d_footer_x d_footer_w add pagestr stringwidth pop sub
    new_marg sub
    d_footer_y 7 add moveto pagestr show
    Helvetica-10-Bold setfont
    d_footer_x new_marg add d_footer_y 7 add moveto last_mod_timestr show
    Helvetica-10-Bold setfont
    d_header_x d_header_w 2 div add fname stringwidth pop 2 div sub
    d_header_y 16 add moveto fname show
  grestore
} def
EOF

enscript --encoding=latin1 --fancy-header=tmp_txt2pdf --word-wrap -p - "$FULL_NAME" | gs -q \
    -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile="$2" -

rm -f $HOME/.enscript/tmp_txt2pdf.hdr

Shell: Lang laufende UNIX jobs mit Benachrichtigung

Folgende Codezeile hilft einem, das Ende eines Jobs nicht zu verpassen. Sobald der Task beendet wurde wird mittels tput bel eine akustische Meldung ausgegeben und ein roter Badge an das Terminalicon im Dock gepackt.

make install && tput bel

Es geht auch noch eleganter, wenn man sich mittels des Ruby GEMS terminal-notifier (bei GitHUB) im Message Center von OS X benachrichtigen lassen will.

terminal-notifier -message "Installation vom Terminal ist fertig!" -title "Terminal hat feddich!"

Shell: FileSharing & FTP-Server von der Konsole aus starten & stoppen

Grade wenn man mehrere Macs im Haus hat (z.B. auch als MediaServer), ist das folgende Kommando ganz praktisch, wenn man sich per SSH auf die Zielmaschine einklinken kann und dann ohne viel Aufwand mal eben FileSharing anknippsen kann. So muss man keinen Bildschirm anschließen und das Einstellungspanel für Sharing-Dienste anklicken.

# Zum Starten des FileSharing
launchctl load -w /System/Library/LaunchDaemons/com.apple.AppleFileServer.plist
# Zum Stoppen des FileSharing
launchctl unload -w /System/Library/LaunchDaemons/com.apple.AppleFileServer.plist

Auf die gleiche Art kann man sich übrigens einen FTP-Serverdienst an- und ausschalten.

# Zum Starten des FTP-Server
launchctl load -w /System/Library/LaunchDaemons/ftp.plist
# Zum Stoppen des FTP-Server
launchctl unload -w /System/Library/LaunchDaemons/ftp.plist

Objective-C: Richtiges escapen von values für URL-Parameter

Leider ist die Methode von NSString stringByAddingPercentEscapesUsingEncoding nicht wirklich brauchbar für das escapen von Zeichen wie z.B. dem &,?,# usw. daher nutze ich folgende Methoden für diese Arbeit.

// String encoden für Verwendung in URL als value
NSString* newEncodeToPercentEscapeString(NSString *string) {
    return (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,(CFStringRef) string,NULL,(CFStringRef) @"!*'();:@&=+$,/?%#[]",kCFStringEncodingUTF8);
}

// String decoden
NSString* newDecodeFromPercentEscapeString(NSString *string) {
    return (NSString *) CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL,(CFStringRef) string, CFSTR(""), kCFStringEncodingUTF8);
}

Aber Achtung der String kommt mit retaincount=1 zurück… man muss den also releasen wenn man fertig ist.

Objective-C: Autolayout im Übergang iOS 5 zu iOS 6

Apple hat mit iOS 6 eine ganze Menge verändert hinsichtlich der bisherigen Layoutfunktionen. U.a. damit sie die neue Displaygröße des iPhone 5 abbilden können. Nervig ist allerdings, dass man während des Übergangs nun für die ganz normale AutoRotation statt wie bisher einer jetzt bis zu fünf Methoden einbauen muss damit sich was dreht. Nämlich folgende:

/**
 * Im AppDelegate
 */

// NEWER IOS >= 6.x
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
    return UIInterfaceOrientationMaskAll;
}

/**
 * Im ViewController
 */

// OLDER IOS < 6.x
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;
}

// NEWER IOS >= 6.x
- (BOOL) shouldAutorotate {
    return YES;
}

// NEWER IOS >= 6.x
- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAll;
}

// NEWER IOS >= 6.x (OPTIONAL)
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return UIInterfaceOrientationPortrait;
}

Tja, da hat man grade das bisherige Layout-System in den Griff bekommen, ändert sich mal wieder alles.

Lästige Warnings im Code von anderen

Gerade wer die Regel verfolgt, „Warnings = Errors“, der ärgert sich über unsauberen Code anderer. Aber in der realität kann man nicht jede Codezeile von anderen fixen, bloss weil da ne Warning hochkommt. Daher kann man sich elegant dieser Warnings wie folgt entledigen, z.B. wenn man weiß das der Code so in Ordnung ist. Man schaltet kurzzeitig die Compilerdiagnostik aus (PUSH einer neuen Regel) für die entsprechenden Warnungen und danach wieder ein (POP der hinzugefügten Diagnoseregel).

// NEUE DIAGNOSEREGEL PUSHEN
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-nonliteral"
- (void)logMessage:(NSString *)format
         level:(LoggingLevel)level withParameters:(va_list)valist {
         if (level >= self.loggingLevel) {
              NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:valist];        
         } 
// HINZUGEFÜGTE DIAGNOSEREGEL ENTFERNEN
#pragma clang diagnostic pop

Einfach, oder? Und hilft auch bei anderen Diagnosealarmen die eher zu den false positives gezählt werden dürfen.

Objective-C: Ein DEBUG-flag, das nicht mehr von Xcode bestimmt/gehijacked wird

Xcode setzt von Haus aus gerne bei einem Development Build das DEBUG flag in den PRECOMPILER STATEMENTS auf TRUE, jedenfalls seit einer Weile schon. Ich beziehe bich öfters auf dieses Flag, um bestimmten Code und bestimmte Code-Bestandteile nur dann auszuführen, wenn die App in Entwicklung ist. Doch ab und an hätte ich ja gerne auch mal einen RUN mit DEBUG = FALSE auch wenn ich einen Development Build fahre. Dafür müsste ich jetzt normalerweise in den Einstellungsscreens (diese Excel-Tabellen-mäßige Parameter-Wüste) das DEBUG Zeug deaktivieren. Schneller und einfacher gehts, wenn man ein eigenes DEBUG flag hat, bei dem man weiß, dass da keiner dran rumdreht auch Xcode nicht. Ich meinen precompiler header files (.pch) mache ich daher oft das Folgende:

// SETUP OWN DEBUG FLAG
#define DEBUG_MASTER 1

// SETUP DEBUG FLAG DEFINED BY XCODE
#ifndef DEBUG
#define DEBUG DEBUG_MASTER
#else
#undef DEBUG
#define DEBUG DEBUG_MASTER
#endif

Wenn man nämlich einfach das DEBUG von Xcode nochmal definiert hilft das nicht und es gibt eine warning. Daher definiere ich das optional weg und definiere es mit meinem MASTER_DEBUG flagzustand neu. Funktioniert zuverlässig!

How Do I Declare A Block in Objective-C?

The following text was copied from a webpage (see footer/source note) because it is really useful for those damn block statements ‚ya know?

As an instance variable:


returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};

As a property:


@property (nonatomic, copy) returnType (^blockName)(parameterTypes);

As a method parameter:


- (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName {...}

As an argument to a method call:


[someObject someMethodThatTakesABlock: ^returnType (parameters) {...}];

As a typedef:


typedef returnType (^TypeName)(parameterTypes);
TypeName blockName = ^(parameters) {...}

Objective-C: Override system locale to have custom app locale at any time

I just want to share a trick on how to gain control over the Locale used for your app. The following code snippet is put in the main-method which kicks of your app.

But basically you should call this code snippet in your app and then make the user quit/terminate the app afterwards to restart with the new set default language AND set these parameters here again depending on a flag you may have stored elsewhere. Because actually all those set default values are actually already used at an earlier point in time i.e. for date formatting.

int main(int argc, char *argv[])
{
    @autoreleasepool {
        
        // OVERRIDE LOCALE (BASICALLY DO THIS WHILE APP RUNS AND LET USER RESTART APP)
        BOOL shouldOverrideLocale = NO; // LET'S TRY TO OVERRIDE IT WITH en_US
        NSString *languageIdentifier = @"en";
        NSString *countryIdentifier = @"US";
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        
        if( shouldOverrideLocale ) {
            NSLog( @"OVERRIDING SYSTEM LOCALE WITH : %@_%@",languageIdentifier, countryIdentifier );
            [defaults setObject:[NSArray arrayWithObject:languageIdentifier] forKey:@"AppleLanguages"];
            [defaults setObject:[NSArray arrayWithObjects:languageIdentifier, nil] forKey:@"NSLanguages"];
            [defaults setObject:[NSString stringWithFormat:@"%@_%@", languageIdentifier, countryIdentifier] forKey:@"AppleLocale"];
            [defaults synchronize];
        }
        else {
            NSArray *keysToRemove = @[@"AppleLanguages",@"NSLanguages",@"AppleLocale"];
            NSLog( @"RESETTING TO USE SYSTEM LOCALE" );
            @try {
                for( NSString *currentKey in keysToRemove ) {
                    if( [defaults objectForKey:currentKey] ) {
                        [defaults removeObjectForKey:currentKey];
                    }
                }
            }
	        @catch (NSException *exception) {
	            // NOTHNG TO CATCH HERE
	        }
	        @finally {
				[defaults synchronize];
	        }
        }
        NSString *languageCode = [[NSLocale autoupdatingCurrentLocale] objectForKey:NSLocaleLanguageCode];
        NSString *countryCode = [[NSLocale autoupdatingCurrentLocale] objectForKey:NSLocaleCountryCode];
        NSLog( @"USING SYSTEM LOCALE: %@_%@", languageCode, countryCode );

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

If you use this code, keep in mind, that strings and processes related to In-App-Purchase are still delivered in the native language of the user.

How to revert pngcrushed aka optimized PNG files in iOS

Xcode does optimized PNG’s when running them through the build system. It makes them non-standard and uneditable by even Photoshop. To restore an image from the assets bundled in your app, you need to revert the optimization process or at least make it a valid PNG again. This is how…

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/pngcrush -revert-iphone-optimizations -q optimized.png reverted.png

Ein Gedanke zu „Code Snippets“

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.