Nsurl Fail Able Initialiser Initwithstring: Does Not Return Nil on Empty String in Swift

NSURL fail able initialiser initWithString: does not return nil on empty String in Swift

After i filled a Radar for this i got the following answer:

Apple Developer Relations

An empty string is a valid URL string. It has no scheme, no authority (user/password/host/port), an empty path, no query and no fragment.

So it seems to be working as expected.

UIDocumentInteractionController nil string parameter

as crash stated, there might be some cases in the logic which are returning nil urlString,
To avoid the crash please add following condition:

if(nil != urlString)
{
NSURL *URL = [[NSURL alloc] initWithString:urlString];
}

or find the root cause which is returning invalid urlString.

Objective-C NSURL With Non-Alphabetical Characters

Problem Description

From the documentation of [NSURL initWithString]

Initializes an NSURL object with a provided URL string.

- (id)initWithString:(NSString *)URLString

Parameters - URLString

The URL string with which to initialize the NSURL object. This URL
string must conform to URL format as described in RFC 2396, and must
not be nil.
This method parses URLString according to RFCs 1738 and
1808.

Return Value

An NSURL object initialized with URLString. If the URL string was
malformed, returns nil.

Discussion

This method expects URLString to contain only characters that are
allowed in a properly formed URL. All other characters must be
properly percent escaped.
Any percent-escaped characters are
interpreted using UTF-8 encoding.

Solution

You need to encode the string as url first. One of the solutions for this is to use
[NSString stringByAddingPercentEscapesUsingEncoding:][1]

There are other discussion on Stackoverflow about encoding strings to urls:

  1. iOS : How to do proper URL encoding?
  2. How do I URL encode a string

Swift. URL returning nil

Don't force unwrap it with (!). When you use (!) and the value of the variable is nil, your program crashes and you get that error. Instead, you want to safely unwrap the optional with either a "guard let" or an "if let" statement.

guard let name = element.Name as? String else {
print("something went wrong, element.Name can not be cast to String")
return
}

if let url = URL(string: "http://en.wikipedia.org/wiki/\(name)") {
UIApplication.shared.openURL(url)
} else {
print("could not open url, it was nil")
}

If that doesn't do the trick, you may have an issue with element.Name. So I would check to see if that's an optional next if you're still having issues.

Update

I added a possible way to check the element.Name property to see if you can cast it as a String and create the desired url you're looking to create. You can see the code above the code I previously posted.

Method Swizzling with Swift 5.5

That's because

@objc internal func log_initWithString(string URLString: String)

is exposed to Objective-C as log_initWithStringWithString: and not as log_initWithString:.

Obvious fix is:

...
let swizzled = Selector("log_initWithStringWithString:")
...

To have better compile time checks on that you can use this syntax:

let original = #selector(NSURL.init(string:))
let swizzled = #selector(NSURL.log_initWithString(string:))

This will compile, but there is at least one thing left to fix - swizzled method return value. In your example:

@objc internal func log_initWithString(string URLString: String) {
NSLog("Hello from initWithString")

return log_initWithString(string: URLString)
}

returns nothing, while NSURL's init is supposed to return NSURL, so the fix is:

@objc internal func log_initWithString(string URLString: String) -> NSURL {
...

How can I make a clickable link in an NSAttributedString?

I found this really useful but I needed to do it in quite a few places so I've wrapped my approach up in a simple extension to NSMutableAttributedString:

Swift 3

extension NSMutableAttributedString {

public func setAsLink(textToFind:String, linkURL:String) -> Bool {

let foundRange = self.mutableString.range(of: textToFind)
if foundRange.location != NSNotFound {
self.addAttribute(.link, value: linkURL, range: foundRange)
return true
}
return false
}
}

Swift 2

import Foundation

extension NSMutableAttributedString {

public func setAsLink(textToFind:String, linkURL:String) -> Bool {

let foundRange = self.mutableString.rangeOfString(textToFind)
if foundRange.location != NSNotFound {
self.addAttribute(NSLinkAttributeName, value: linkURL, range: foundRange)
return true
}
return false
}
}

Example usage:

let attributedString = NSMutableAttributedString(string:"I love stackoverflow!")
let linkWasSet = attributedString.setAsLink("stackoverflow", linkURL: "http://stackoverflow.com")

if linkWasSet {
// adjust more attributedString properties
}

Objective-C

I've just hit a requirement to do the same in a pure Objective-C project, so here's the Objective-C category.

@interface NSMutableAttributedString (SetAsLinkSupport)

- (BOOL)setAsLink:(NSString*)textToFind linkURL:(NSString*)linkURL;

@end

@implementation NSMutableAttributedString (SetAsLinkSupport)

- (BOOL)setAsLink:(NSString*)textToFind linkURL:(NSString*)linkURL {

NSRange foundRange = [self.mutableString rangeOfString:textToFind];
if (foundRange.location != NSNotFound) {
[self addAttribute:NSLinkAttributeName value:linkURL range:foundRange];
return YES;
}
return NO;
}

@end

Example usage:

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:"I love stackoverflow!"];

BOOL linkWasSet = [attributedString setAsLink:@"stackoverflow" linkURL:@"http://stackoverflow.com"];

if (linkWasSet) {
// adjust more attributedString properties
}

Make Sure that the NSTextField's Behavior attribute is set as Selectable.
Xcode NSTextField behavior attribute



Related Topics



Leave a reply



Submit