【问题标题】:Change a NSURL's scheme更改 NSURL 的方案
【发布时间】:2013-01-18 05:37:08
【问题描述】:

有没有一种简单的方法可以更改NSURL 的方案?我确实意识到NSURL 是不可变的。我的目标是如果链接了Security.framework,则将 URL 的方案更改为“https”,如果未链接框架,则将其更改为“http”。我确实知道如何检测框架是否已链接。

如果 URL 没有参数(例如“?param1=foo&param2=bar”),此代码将非常有效:

+(NSURL*)adjustURL:(NSURL*)inURL toSecureConnection:(BOOL)inUseSecure {
    if ( inUseSecure ) {
        return [[[NSURL alloc] initWithScheme:@"https" host:[inURL host] path:[inURL path]] autorelease];
    }
    else {
        return [[[NSURL alloc] initWithScheme:@"http" host:[inURL host] path:[inURL path]] autorelease];
    }    
}

但如果 URL 确实有参数,[inURL path] 会丢弃它们。

除了自己解析 URL 字符串之外还有什么建议(我可以这样做,但我想尝试不这样做)?我做了什么能够将带有 http 或 https 的 URL 传递给此方法。

【问题讨论】:

    标签: ios


    【解决方案1】:

    更新答案

    NSURLComponents 是你的朋友。您可以使用它将http 方案替换为https。唯一需要注意的是 NSURLComponents 使用 RFC 3986,而 NSURL 使用较旧的 RFC 1738 和 1808,因此在极端情况下存在一些行为差异,但您极不可能遇到这些情况(NSURLComponents 更好无论如何行为)。

    NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:YES];
    components.scheme = inUseSecure ? @"https" : @"http";
    return components.URL;
    

    原答案

    为什么不做一些字符串操作呢?

    NSString *str = [url absoluteString];
    NSInteger colon = [str rangeOfString:@":"].location;
    if (colon != NSNotFound) { // wtf how would it be missing
        str = [str substringFromIndex:colon]; // strip off existing scheme
        if (inUseSecure) {
            str = [@"https" stringByAppendingString:str];
        } else {
            str = [@"http" stringByAppendingString:str];
        }
    }
    return [NSURL URLWithString:str];
    

    【讨论】:

    • 是的,这不是我想做的,但考虑到NSURL的界面,它似乎是最合适的。
    【解决方案2】:

    如果您使用的是 iOS 7 及更高版本,则可以使用NSURLComponents,如显示here

    NSURLComponents *components = [NSURLComponents new];
    components.scheme = @"http";
    components.host = @"joris.kluivers.nl";
    components.path = @"/blog/2013/10/17/nsurlcomponents/";
    
    NSURL *url = [components URL];
    // url now equals:
    // http://joris.kluivers.nl/blog/2013/10/17/nsurlcomponents/
    

    【讨论】:

    • 我会推荐使用 NSURLComponents *components = [NSURLComponents componentsWithURL:URL resolveAgainstBaseURL:NO];
    【解决方案3】:

    Swift5

    extension URL {
        func settingScheme(_ value: String) -> URL {
        let components = NSURLComponents.init(url: self, resolvingAgainstBaseURL: true)
        components?.scheme = value
        return (components?.url!)!
    }
    

    }

    用法

    if nil == url.scheme { url = url.settingScheme("file") }
    

    【讨论】:

      【解决方案4】:

      也许使用resourceSpecifier 会有所帮助:

      return [[[NSURL alloc] initWithString:[NSString stringWithFormat:@"https:%@", [inURL resourceSpecifier]]]];
      

      【讨论】:

        【解决方案5】:
        NSString *newUrlString =  [NSString stringWithFormat:@"https://%@%@", 
                                  inURL.host, inURL.path];
        if (inURL.query) {
            newUrlString = [newUrlString stringByAppendingFormat:@"?%@", inURL.query];
        }
        return [NSURL URLWithString:newUrl];
        

        [注意] 为简单起见,删除了与端口和其他字段处理相关的代码。

        【讨论】:

        • 缺少其他字段,例如“片段”和“端口”。 (参考:ietf.org/rfc/rfc3986.txt
        • @HKTonyLee 我知道。这不是一般的 url 重建。问题中也缺少端口和片段。只是告诉他 url.query 是他想要的。
        【解决方案6】:

        我是这样做的,在 NSURL 中使用变量 resourceSpecifier

        SWIFT

        var resourceSpecifier: String? { get } 
        

        目标-C

        @property(readonly, copy) NSString *resourceSpecifier Discussion 
        

        此属性包含资源说明符。例如,在 URL http://www.example.com/index.html?key1=value1#jumplink 中,资源说明符是 //www.example.com/index.html?key1=value1#jumplink(冒号后面的所有内容)。

          -(NSURL*) URLByReplacingScheme
            {
                NSString *newUrlString = kHttpsScheme;
        
                if([self.scheme isEqualToString:kEmbeddedScheme])
                    newUrlString = kHttpScheme;
        
                newUrlString = [newUrlString stringByAppendingString:[NSString stringWithFormat:@":%@", self.resourceSpecifier]];
        
                return [NSURL URLWithString:newUrlString];
            }
        

        【讨论】:

        猜你喜欢
        • 2011-05-12
        • 2013-07-31
        • 2011-01-07
        • 2012-07-06
        • 1970-01-01
        • 2021-05-06
        • 2017-10-30
        • 2012-08-30
        • 2017-12-05
        相关资源
        最近更新 更多