Logging in Swift 2.0 - xcode

I am new to XCode and work on Android Studio previously. In Android Studio, there is log cat to log different types of messages for debugging purposes.
Is this available in XCode?
All I found is NSLog which prints the date and the statement without coloring like in log cat. Is there an easier way ?

You can use the print method.
Check out these handy Apple docs.
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html

using XCodeColors Library https://github.com/robbiehanson/XcodeColors you can log different types of messages each in a unique color so that you can find error logs faster
also i customized the code like this to get coloring, which class, function, and line number did the call
struct RZLog
{
static let ESCAPE = "\u{001b}["
static let RESET_FG = ESCAPE + "fg;" // Clear any foreground color
static let RESET_BG = ESCAPE + "bg;" // Clear any background color
static let RESET = ESCAPE + ";" // Clear any foreground or background color
static let A = "fg255,0,0;"
static let B = "fg0,0,255;"
static let C = "fg16,128,0;"
static func Error<T>(object: T, filename: String = FILE, line: Int = LINE, funcname: String = FUNCTION) {
let ClassName = NSURL(string: filename)!
print("\(ESCAPE)\(A)**ERROR \(ClassName.lastPathComponent!)(\(line)) Func: \(funcname.uppercaseString): \(object) **\(RESET)")
}
static func Debug<T>(object: T, filename: String = FILE, line: Int = LINE, funcname: String = FUNCTION) {
let ClassName = NSURL(string: filename)!
print("\(ESCAPE)\(B)**DEBUG \(ClassName.lastPathComponent!)(\(line)) Func: \(funcname.uppercaseString): \(object) **\(RESET)")
}
static func VIP<T>(object: T, filename: String = FILE, line: Int = LINE, funcname: String = FUNCTION) {
let ClassName = NSURL(string: filename)!
print("\(ESCAPE)\(C)**VIP \(ClassName.lastPathComponent!)(\(line)) Func: \(funcname.uppercaseString): \(object) **\(RESET)")
}
}

If you want to use different CocoaLumberjack:
https://github.com/CocoaLumberjack/CocoaLumberjack
Which provides some more advantages over simple logging. And it can also be used with colors:
http://code.tutsplus.com/tutorials/cocoalumberjack-logging-on-steroids--mobile-15287

You can use Printer a new logging experience in Swift 3.x.
It has many functions to add logs in various ways.
Usage:
To log a success message:
Printer.log.success(details: "This is a Success message.")
Output:
Printer ➞ [✅ Success] [⌚04-27-2017 10:53:28] ➞ ✹✹This is a Success message.✹✹
[Trace] ➞ ViewController.swift ➞ viewDidLoad() #58
Disclaimer: This library has been created by me.

Related

What does Some() do on the left hand side of a variable assignment?

I was reading some Rust code and I came across this line
if let Some(path) = env::args().nth(1) {
Inside of this function
fn main() {
if let Some(path) = env::args().nth(1) {
// Try reading the file provided by the path.
let mut file = File::open(path).expect("Failed reading file.");
let mut content = String::new();
file.read_to_string(&mut content);
perform_conversion(content.as_str()).expect("Conversion failed.");
} else {
println!(
"provide a path to a .cue file to be converted into a MusicBrainz compatible tracklist."
)
}
}
The line seems to be assigning the env argument to the variable path but I can't work out what the Some() around it is doing.
I took a look at the documentation for Option and I understand how it works when used on the right hand side of = but on the left hand side I am a little confused.
Am I right in thinking this line is equivalent to
if let path = Some(env::args().nth(1)) {
From the reference :
An if let expression is semantically similar to an if expression but
in place of a condition expression it expects the keyword let followed
by a refutable pattern, an = and an expression. If the value of the
expression on the right hand side of the = matches the pattern, the
corresponding block will execute, otherwise flow proceeds to the
following else block if it exists. Like if expressions, if let
expressions have a value determined by the block that is evaluated.
In here the important part is refutability. What it means refutable pattern in here it can be in different forms. For example :
enum Test {
First(String, i32, usize),
Second(i32, usize),
Third(i32),
}
You can check the x's value for a value for 3 different pattern like :
fn main() {
let x = Test::Second(14, 55);
if let Test::First(a, b, c) = x {}
if let Test::Second(a, b) = x {} //This block will be executed
if let Test::Third(a) = x {}
}
This is called refutability. But consider your code like this:
enum Test {
Second(i32, usize),
}
fn main() {
let x = Test::Second(14, 55);
if let Test::Second(a, b) = x {}
}
This code will not compile because x's pattern is obvious, it has single pattern.
You can get more information from the reference of refutability.
Also you are not right thinking for this:
if let path = Some(env::args().nth(1)) {
Compiler will throw error like irrefutable if-let pattern because as the reference says: "keyword let followed by a refutable pattern". In here there is no refutable pattern after "let". Actually this code tries to create a variable named path which is an Option and this make no sense because there is no "If" needed,
Instead Rust expects from you to write like this:
let path = Some(env::args().nth(1)); // This will be seem like Some(Some(value))
The other answers go into a lot of detail, which might be more than you need to know.
Essentially, this:
if let Some(path) = env::args().nth(1) {
// Do something with path
} else {
// otherwise do something else
}
is identical to this:
match env::args().nth(1) {
Some(path) => { /* Do something with path */ }
_ => { /* otherwise do something else */ }
}

NSTask : Couldn't posix_spawn: error 13 when launching app

I have a sub-app in my main Swift app. I made it so it's copied automatically in the Resources folder of the main app when building it. That way, I want to be able to launch an instance of the sub-app from the main app.
The thing is, I'm having an error that is hard to debug/find answers about.
Here is my code :
let args = ["--args", "-admin_url", site.url, "-login", site.login, "-pass", site.password]
let helperPath = (NSBundle.mainBundle().pathForResource("App Helper", ofType: "app"))!
let task = NSTask.init()
task.launchPath = helperPath
task.arguments = args
task.launch()
And the error :
[56490:7218926] Couldn't posix_spawn: error 13
I have no idea where to look, what to search for. I don't know what I'm doing wrong.
I'm wondering if the issue is related to the sub-app itself. That sub-app is empty for now. I set Application is Agent to YES. And in MainMenu.xib, I set the Visible at launch option to no.
That sub-app needs to do some work in the background and doesn't need any UI at all.
Thanks !
Don't use NSTask for this, use NSWorkspace:
let helperAppURL = NSBundle.mainBundle().URLForResource("App Helper",
withExtension:"app")!
_ = try? NSWorkspace.sharedWorkspace().openURL(helperAppURL,
options:[.Default],
configuration:[NSWorkspaceLaunchConfigurationArguments :
["--args", "-admin_url", site.url, "-login",
site.login, "-pass", site.password]])
In the above code, for brevity, I ignored the result of the openURL() command, but in reality it can return an instance of NSRunningApplication which represents the task.
To keep track of the instances of your helper app you launch, you could keep references to this NSRunningApplication in an appropriate kind of collection class, and when the time comes, call its terminate() method.
the launch() function is deprecated, using run()
func shell(_ command: String) -> String {
let task = Process()
task.launchPath = "/usr/bin/"
task.arguments = ["-c", command]
let pipe = Pipe()
task.standardOutput = pipe
if #available(macOS 10.13, *) {
try? task.run()
} else {
task.launch()
}
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue)! as String
return output
}
or using swift-commands
import Commands
Commands.Bash.run("say hello")

How to replace emoji characters with their descriptions in a Swift string

I'm looking for a way to replace emoji characters with their description in a Swift string.
Example:
Input "This is my string 😄"
I'd like to replace the 😄 to get:
Output "This is my string {SMILING FACE WITH OPEN MOUTH AND SMILING EYES}"
To date I'm using this code modified from the original code of this answer by MartinR, but it works only if I deal with a single character.
let myCharacter : Character = "😄"
let cfstr = NSMutableString(string: String(myCharacter)) as CFMutableString
var range = CFRangeMake(0, CFStringGetLength(cfstr))
CFStringTransform(cfstr, &range, kCFStringTransformToUnicodeName, Bool(0))
var newStr = "\(cfstr)"
// removing "\N" from the result: \N{SMILING FACE WITH OPEN MOUTH AND SMILING EYES}
newStr = newStr.stringByReplacingOccurrencesOfString("\\N", withString:"")
print("\(newStr)") // {SMILING FACE WITH OPEN MOUTH AND SMILING EYES}
How can I achieve this?
Simply do not use a Character in the first place but use a String as input:
let cfstr = NSMutableString(string: "This 😄 is my string 😄") as CFMutableString
that will finally output
This {SMILING FACE WITH OPEN MOUTH AND SMILING EYES} is my string {SMILING FACE WITH OPEN MOUTH AND SMILING EYES}
Put together:
func transformUnicode(input : String) -> String {
let cfstr = NSMutableString(string: input) as CFMutableString
var range = CFRangeMake(0, CFStringGetLength(cfstr))
CFStringTransform(cfstr, &range, kCFStringTransformToUnicodeName, Bool(0))
let newStr = "\(cfstr)"
return newStr.stringByReplacingOccurrencesOfString("\\N", withString:"")
}
transformUnicode("This 😄 is my string 😄")
Here is a complete implementation.
It avoids to convert to description also the non-emoji characters (e.g. it avoids to convert “ to {LEFT DOUBLE QUOTATION MARK}). To accomplish this, it uses an extension based on this answer by Arnold that returns true or false whether a string contains an emoji.
The other part of the code is based on this answer by MartinR and the answer and comments to this answer by luk2302.
var str = "Hello World 😄 …" // our string (with an emoji and a horizontal ellipsis)
let newStr = str.characters.reduce("") { // loop through str individual characters
var item = "\($1)" // string with the current char
let isEmoji = item.containsEmoji // true or false
if isEmoji {
item = item.stringByApplyingTransform(String(kCFStringTransformToUnicodeName), reverse: false)!
}
return $0 + item
}.stringByReplacingOccurrencesOfString("\\N", withString:"") // strips "\N"
extension String {
var containsEmoji: Bool {
for scalar in unicodeScalars {
switch scalar.value {
case 0x1F600...0x1F64F, // Emoticons
0x1F300...0x1F5FF, // Misc Symbols and Pictographs
0x1F680...0x1F6FF, // Transport and Map
0x2600...0x26FF, // Misc symbols
0x2700...0x27BF, // Dingbats
0xFE00...0xFE0F, // Variation Selectors
0x1F900...0x1F9FF: // Various (e.g. 🤖)
return true
default:
continue
}
}
return false
}
}
print (newStr) // Hello World {SMILING FACE WITH OPEN MOUTH AND SMILING EYES} …
Please note that some emoji could not be included in the ranges of this code, so you should check if all the emoji are converted at the time you will implement the code.

Temporary file path using swift

How to get a unique temporary file path using Swift/Cocoa on OS X?
Cocoa does not seem to provide a function for this, only NSTemporaryDirectory() which returns the path of the temporary directory. Using the BSD mktemp function requires a mutable C-string as argument.
Apple has been trying to move away from path-as-string and into NSURL. Here's one way:
Swift 3:
let directory = NSTemporaryDirectory()
let fileName = NSUUID().uuidString
// This returns a URL? even though it is an NSURL class method
let fullURL = NSURL.fileURL(withPathComponents: [directory, fileName])
Swift 2:
let directory = NSTemporaryDirectory()
let fileName = NSUUID().UUIDString
let fullURL = NSURL.fileURLWithPathComponents([directory, fileName])
Here is a possible method to use mkstemp() from Swift 3 and later. URL methods
are used to convert between URL instances and C strings representing the file system path:
// The template string:
let template = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("file.XXXXXX") as NSURL
// Fill buffer with a C string representing the local file system path.
var buffer = [Int8](repeating: 0, count: Int(PATH_MAX))
template.getFileSystemRepresentation(&buffer, maxLength: buffer.count)
// Create unique file name (and open file):
let fd = mkstemp(&buffer)
if fd != -1 {
// Create URL from file system string:
let url = URL(fileURLWithFileSystemRepresentation: buffer, isDirectory: false, relativeTo: nil)
print(url.path)
} else {
print("Error: " + String(cString: strerror(errno)))
}
Older code for Swift 2:
// The template string:
let template = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent("file.XXXXXX")
// Fill buffer with a C string representing the local file system path.
var buffer = [Int8](count: Int(PATH_MAX), repeatedValue: 0)
template.getFileSystemRepresentation(&buffer, maxLength: buffer.count)
// Create unique file name (and open file):
let fd = mkstemp(&buffer)
if fd != -1 {
// Create URL from file system string:
let url = NSURL(fileURLWithFileSystemRepresentation: buffer, isDirectory: false, relativeToURL: nil)
print(url.path!)
} else {
print("Error: " + String(strerror(errno)))
}
Although NSTemporaryDirectory() does indeed return a temporary directory path for the current user, the documentation includes the following caveat:
See the FileManager method url(for:in:appropriateFor:create:) for the preferred means of finding the correct temporary directory.
Following that link, we are presented with the following:
You can use this method to create a new temporary directory. To do so, specify FileManager.SearchPathDirectory.itemReplacementDirectory for the directory parameter, userDomainMask for the domain parameter, and a URL for the url parameter which determines the volume of the returned URL.
For example, the following code results in a new temporary directory with a path in the form of /private/var/folders/d0/h37cw8ns3h1bfr_2gnwq2yyc0000gn/T/TemporaryItems/Untitled/:
let desktop = URL(fileURLWithPath: "/Users/jappleseed/Desktop/")
do {
let temporaryDirectory = try FileManager.default.url(
for: .itemReplacementDirectory,
in: .userDomainMask,
appropriateFor: desktop,
create: true
)
print(temporaryDirectory)
} catch {
// Handle the error.
}
(Note the the create parameter is ignored when creating a temporary directory.)
So what exactly is the difference between these two approaches? Well, here's what I get when I call the two different methods from the Swift REPL:
1> import Foundation
2> NSTemporaryDirectory()
$R0: String = "/var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/"
3> let desktop = URL(fileURLWithPath: "/Users/chris/Desktop/")
desktop: URL = "file:///Users/chris/Desktop/"
4> let temporaryDirectory = try FileManager.default.url(
5. for: .itemReplacementDirectory,
6. in: .userDomainMask,
7. appropriateFor: desktop,
8. create: true
9. )
temporaryDirectory: URL = "file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20repl_swift)/"
It appears that NSTemporaryDirectory() will always return the temporary directory path for the current user whereas FileManager's url(for:appropriateFor:create) will return a new temporary subdirectory each time it is called. For example, here are the directories returned by consecutive calls to url(for:in:appropriateFor:create:) from the Swift REPL:
file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20repl_swift)/
file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20repl_swift%202)/
file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20repl_swift%203)/
And here are the directories returned by consecutive calls to the same method from a Swift Playground:
file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20Xcode)/
file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20Xcode%202)/
file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20Xcode%203)/
The NSHipster article on temporary files seems to suggest that the FileManager method url(for:in:appropriateFor:create:) is intended to be used when staging a file to be moved to a more permanent location (such as the user's desktop in the example above), but I don't see why it couldn't also be used to simply get a unique subdirectory that will automatically be removed when you're done with it and where you shouldn't have to worry about files getting accidentally clobbered by other processes writing to the same temporary directory.
A Swift 3 one-liner inspired by the UUID based Swift 2 answer:
let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString)
FileManager extension in Swift to get a temporary file URL. You can pass your own file name and extension, if needed.
public extension FileManager {
func temporaryFileURL(fileName: String = UUID().uuidString) -> URL? {
return URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent(fileName)
}
}
Usage:
let tempURL = FileManager.default.temporaryFileURL()
let tempJPG = FileManager.default.temporaryFileURL(fileName: "temp.jpg")
Use a GUID (Globally Unique Identifier):
let directory :NSString = "directory"
let randomName = NSProcessInfo().globallyUniqueString
let path = directory.stringByAppendingPathComponent(randomName)
directory/3B635E49-813A-4324-B4B8-56279B42BEAB-36687-0002D962615DAE5F
I like the idea of this article: NSTemporary​Directory - NSHipster
This uses the NSTemporaryDirectory() for the temporary folder and ProcessInfo.processInfo.globallyUniqueString to generate a unique string.
Swift 4:
func uniqueTempFolderURL() -> URL
{
let folderName = ProcessInfo.processInfo.globallyUniqueString
return URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent(folderName)
}
Swift3
I came here looking for something like boost::filesystem::unique_path()
So I made this extension to the URL class.
extension URL {
func appendingUniquePathComponent(pathExtension: String? = nil) -> URL {
var pathComponent = UUID().uuidString
if let pathExtension = pathExtension {
pathComponent += ".\(pathExtension)"
}
return appendingPathComponent(pathComponent)
}
}
Usage:
let url0 = URL(fileURLWithPath: "/tmp/some/dir")
let url1 = url0.appendingUniquePathComponent(pathExtension: "jpg")
print("url1: \(url1)")
// url1: file:///tmp/some/dir/936324FF-EEDB-410E-AD09-E24D5EB4A24F.jpg

Check Mac battery percentage in swift

I have been trying to check the mac battery level programmatically.it can be done on ios but i want to do it in mac.i found some resources on stackoverflow but those links were deprecated. Any Ideas?
First create a "Umbrella-Bridging-Header.h"
with the content:
#import <IOKit/ps/IOPowerSources.h>
then in main.swift
import Foundation
println("Hello, World!")
let timeRemaining = IOPSGetTimeRemainingEstimate ()
println("timeRemaining: \(timeRemaining)")
If you don't want to add Objective-C bridging and you need just to know a couple of values. Then you could use this function.
func getBatteryState() -> [String?]
{
let task = Process()
let pipe = Pipe()
task.launchPath = "/usr/bin/pmset"
task.arguments = ["-g", "batt"]
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String
let batteryArray = output.components(separatedBy: ";")
let source = output.components(separatedBy: "'")[1]
let state = batteryArray[1].trimmingCharacters(in: NSCharacterSet.whitespaces).capitalized
let percent = String.init(batteryArray[0].components(separatedBy: ")")[1].trimmingCharacters(in: NSCharacterSet.whitespaces).characters.dropLast())
var remaining = String.init(batteryArray[2].characters.dropFirst().split(separator: " ")[0])
if(remaining == "(no"){
remaining = "Calculating"
}
return [source, state, percent, remaining]
}
print(getBatteryState().flatMap{$0}) -> "AC Power", "Discharging", "94", "3:15"
pmset is a very old command line function which is very unlikely to change in the future. Of course this does not give extended properties of power options like mAh and so on, but it was enough for me, because I just needed to know is it charging or not and how much percent battery has currently.
Just my 2 cents. I understand if people will find this discouraging to use.
N.B. If charging - remaining will show how long until it's fully charged.
If discharging - it will show how long until it's discharged.
First, you can see the answer here on how to include Objective-C code in your swift project (very good post btw).
Then, check out the IOMPowerSource class. It should include everything you need to report the status of the computer's power information.
Swift 2 Version of the answer of #Just A Minnion
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var label: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
label.stringValue = String(getBatteryState().flatMap{$0})
}
func getBatteryState() -> [String?] {
let task = NSTask()
let pipe = NSPipe()
task.launchPath = "/usr/bin/pmset"
task.arguments = ["-g", "batt"]
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = NSString(data: data, encoding: NSUTF8StringEncoding) as! String
let batteryArray = output.componentsSeparatedByString(";")
let source = output.componentsSeparatedByString("'")[1]
let state = batteryArray[0].stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).capitalizedString
let percent = String.init(batteryArray[0].componentsSeparatedByString(")")[0].stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()))
var remaining = String.init(batteryArray[0].characters.dropFirst().split(" ")[1])
if (remaining == "(no") {
remaining = "Calculating"
}
return [source, state, percent, remaining]
}
}

Resources