Mam taki adres URL myApp://action/1?parameter=2&secondparameter=3
Wraz z zapytaniem o właściwość otrzymuję część pliku URL
parameter=2&secondparameter=3
Czy jest jakiś sposób łatwy do umieszczenia tego w a NSDictionary
lub an Array
?
Wielkie dzięki
iphone
objective-c
nsurl
gabac
źródło
źródło
[params setObject:[elts lastObject] forKey:[elts firstObject]];
jest bezpieczniejszyMożesz użyć
queryItems
wURLComponents
.Szybki
let url = "http://example.com?param1=value1¶m2=param2" let queryItems = URLComponents(string: url)?.queryItems let param1 = queryItems?.filter({$0.name == "param1"}).first print(param1?.value)
Alternatywnie możesz dodać rozszerzenie do adresu URL, aby ułatwić sprawę.
extension URL { var queryParameters: QueryParameters { return QueryParameters(url: self) } } class QueryParameters { let queryItems: [URLQueryItem] init(url: URL?) { queryItems = URLComponents(string: url?.absoluteString ?? "")?.queryItems ?? [] print(queryItems) } subscript(name: String) -> String? { return queryItems.first(where: { $0.name == name })?.value } }
Możesz wtedy uzyskać dostęp do parametru poprzez jego nazwę.
let url = "http://example.com?param1=value1¶m2=param2" print(url.queryParameters["param1"])
źródło
http://example.com/abc#abc?param1=value1¶m2=param2
queryItems będzie zeroweMiałem powód, aby napisać kilka rozszerzeń dla tego zachowania, które mogą się przydać. Najpierw nagłówek:
#import <Foundation/Foundation.h> @interface NSString (XQueryComponents) - (NSString *)stringByDecodingURLFormat; - (NSString *)stringByEncodingURLFormat; - (NSMutableDictionary *)dictionaryFromQueryComponents; @end @interface NSURL (XQueryComponents) - (NSMutableDictionary *)queryComponents; @end @interface NSDictionary (XQueryComponents) - (NSString *)stringFromQueryComponents; @end
Te metody rozszerzają NSString, NSURL i NSDictionary, aby umożliwić konwersję do iz ciągów składników zapytania i obiektów słownika zawierających wyniki.
Teraz powiązany kod .m:
#import "XQueryComponents.h" @implementation NSString (XQueryComponents) - (NSString *)stringByDecodingURLFormat { NSString *result = [self stringByReplacingOccurrencesOfString:@"+" withString:@" "]; result = [result stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; return result; } - (NSString *)stringByEncodingURLFormat { NSString *result = [self stringByReplacingOccurrencesOfString:@" " withString:@"+"]; result = [result stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; return result; } - (NSMutableDictionary *)dictionaryFromQueryComponents { NSMutableDictionary *queryComponents = [NSMutableDictionary dictionary]; for(NSString *keyValuePairString in [self componentsSeparatedByString:@"&"]) { NSArray *keyValuePairArray = [keyValuePairString componentsSeparatedByString:@"="]; if ([keyValuePairArray count] < 2) continue; // Verify that there is at least one key, and at least one value. Ignore extra = signs NSString *key = [[keyValuePairArray objectAtIndex:0] stringByDecodingURLFormat]; NSString *value = [[keyValuePairArray objectAtIndex:1] stringByDecodingURLFormat]; NSMutableArray *results = [queryComponents objectForKey:key]; // URL spec says that multiple values are allowed per key if(!results) // First object { results = [NSMutableArray arrayWithCapacity:1]; [queryComponents setObject:results forKey:key]; } [results addObject:value]; } return queryComponents; } @end @implementation NSURL (XQueryComponents) - (NSMutableDictionary *)queryComponents { return [[self query] dictionaryFromQueryComponents]; } @end @implementation NSDictionary (XQueryComponents) - (NSString *)stringFromQueryComponents { NSString *result = nil; for(__strong NSString *key in [self allKeys]) { key = [key stringByEncodingURLFormat]; NSArray *allValues = [self objectForKey:key]; if([allValues isKindOfClass:[NSArray class]]) for(__strong NSString *value in allValues) { value = [[value description] stringByEncodingURLFormat]; if(!result) result = [NSString stringWithFormat:@"%@=%@",key,value]; else result = [result stringByAppendingFormat:@"&%@=%@",key,value]; } else { NSString *value = [[allValues description] stringByEncodingURLFormat]; if(!result) result = [NSString stringWithFormat:@"%@=%@",key,value]; else result = [result stringByAppendingFormat:@"&%@=%@",key,value]; } } return result; } @end
źródło
Spróbuj tego ;)!
NSString *query = @"parameter=2&secondparameter=3"; // replace this with [url query]; NSArray *components = [query componentsSeparatedByString:@"&"]; NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init]; for (NSString *component in components) { NSArray *subcomponents = [component componentsSeparatedByString:@"="]; [parameters setObject:[[subcomponents objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] forKey:[[subcomponents objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; }
źródło
Wszystkie poprzednie posty nie kodują poprawnie adresu URL. Sugerowałbym następujące metody:
+(NSString*)concatenateQuery:(NSDictionary*)parameters { if([parameters count]==0) return nil; NSMutableString* query = [NSMutableString string]; for(NSString* parameter in [parameters allKeys]) [query appendFormat:@"&%@=%@",[parameter stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet],[[parameters objectForKey:parameter] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]]; return [[query substringFromIndex:1] copy]; } +(NSDictionary*)splitQuery:(NSString*)query { if([query length]==0) return nil; NSMutableDictionary* parameters = [NSMutableDictionary dictionary]; for(NSString* parameter in [query componentsSeparatedByString:@"&"]) { NSRange range = [parameter rangeOfString:@"="]; if(range.location!=NSNotFound) [parameters setObject:[[parameter substringFromIndex:range.location+range.length] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] forKey:[[parameter substringToIndex:range.location] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; else [parameters setObject:[[NSString alloc] init] forKey:[parameter stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; } return [parameters copy]; }
źródło
if(!query||[query length] == 0)
jest zbędny. Możesz bezpiecznie sprawdzić,if([query length] == 0)
jak w przypadkuquery == nil
, gdy zwróci wartość,0
jeśli spróbujesz wywołać na nim długość.NSUTF8StringEncoding
wsplitQuery
do obsługi wszystkich zestawów znaków :)[string stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]
Jest też nowszy sposób kodowaniaconcatenateQuery
.Oto rozszerzenie w szybkim:
extension NSURL{ func queryParams() -> [String:AnyObject] { var info : [String:AnyObject] = [String:AnyObject]() if let queryString = self.query{ for parameter in queryString.componentsSeparatedByString("&"){ let parts = parameter.componentsSeparatedByString("=") if parts.count > 1{ let key = (parts[0] as String).stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding) let value = (parts[1] as String).stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding) if key != nil && value != nil{ info[key!] = value } } } } return info } }
źródło
Zgodnie z już bardzo czystą odpowiedzią Onato , napisałem rozszerzenie NSURL w Swift, w którym można uzyskać taki parametr zapytania:
np. URL zawiera parę param = some_value
let queryItem = url.queryItemForKey("param") let value = queryItem.value // would get String "someValue"
Rozszerzenie wygląda następująco:
extension NSURL { var allQueryItems: [NSURLQueryItem] { get { let components = NSURLComponents(URL: self, resolvingAgainstBaseURL: false)! let allQueryItems = components.queryItems! return allQueryItems as [NSURLQueryItem] } } func queryItemForKey(key: String) -> NSURLQueryItem? { let predicate = NSPredicate(format: "name=%@", key)! return (allQueryItems as NSArray).filteredArrayUsingPredicate(predicate).first as? NSURLQueryItem } }
źródło
Dla osób używających Bolts Framework możesz użyć:
NSDictionary *parameters = [BFURL URLWithURL:yourURL].inputQueryParameters;
Pamiętaj, aby zaimportować:
#import <Bolts/BFURL.h>
Jeśli zdarzyło Ci się mieć w swoim projekcie Facebook SDK , masz również Bolts . Facebook używa tej struktury jako zależności.
źródło
BFURL(url: url)?.inputQueryParameters?["myKey"] as? String
Preferowanym sposobem radzenia sobie z adresami URL jest teraz
NSURLComponents
. W szczególnościqueryItems
właściwość, która zwraca wartośćNSArray
z params.Jeśli chcesz, aby parametry w a
NSDictionary
, oto metoda:+(NSDictionary<NSString *, NSString *>*)queryParamsFromURL:(NSURL*)url { NSURLComponents* urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO]; NSMutableDictionary<NSString *, NSString *>* queryParams = [NSMutableDictionary<NSString *, NSString *> new]; for (NSURLQueryItem* queryItem in [urlComponents queryItems]) { if (queryItem.value == nil) { continue; } [queryParams setObject:queryItem.value forKey:queryItem.name]; } return queryParams; }
Uwaga: adresy URL mogą mieć powtarzające się parametry, ale słownik będzie zawierał tylko ostatnią wartość dowolnego zduplikowanego parametru. Jeśli jest to niepożądane, użyj
queryItems
tablicy bezpośrednio.źródło
Swift 2.1
Oneliner:
"p1=v1&p2=v2".componentsSeparatedByString("&").map { $0.componentsSeparatedByString("=") }.reduce([:]) { (var dict: [String:String], p) in dict[p[0]] = p[1] return dict } // ["p1": "v1", "p2": "v2"]
Używany jako rozszerzenie NSURL:
extension NSURL { /** * URL query string as dictionary. Empty dictionary if query string is nil. */ public var queryValues : [String:String] { get { if let q = self.query { return q.componentsSeparatedByString("&").map { $0.componentsSeparatedByString("=") }.reduce([:]) { (var dict: [String:String], p) in dict[p[0]] = p[1] return dict } } else { return [:] } } } }
Przykład:
let url = NSURL(string: "http://example.com?p1=v1&p2=v2")! let queryDict = url.queryValues // ["p1": "v1", "p2": "v2"]
Należy pamiętać, że jeśli używasz OS X 10.10 lub iOS 8 (lub nowszego), prawdopodobnie lepiej jest użyć
NSURLComponents
iqueryItems
właściwości i utworzyć słownikNSURLQueryItems
bezpośrednio z.Oto rozwiązanie
NSURLComponents
oparte naNSURL
rozszerzeniu:extension NSURL { /// URL query string as a dictionary. Empty dictionary if query string is nil. public var queryValues : [String:String] { get { guard let components = NSURLComponents(URL: self, resolvingAgainstBaseURL: false) else { return [:] } guard let queryItems = components.queryItems else { return [:] } var result:[String:String] = [:] for q in queryItems { result[q.name] = q.value } return result } } }
Przypisem do rozszerzenia NSURL jest to, że w języku Swift można nadać właściwości taką samą nazwę, jak istniejąca właściwość ciągu -
query
. Nie wiedziałem, dopóki tego nie wypróbowałem, ale polimorfizm w Swift pozwala ci różnić się tylko typem zwrotu. Więc jeśli rozszerzona właściwość NSURLpublic var query: [String:String]
działa. Nie użyłem tego w przykładzie, ponieważ uważam to za trochę szalone, ale działa ...źródło
Opublikowałem proste zajęcia wykonujące pracę w ramach MIT:
https://github.com/anegmawad/URLQueryToCocoa
Dzięki niemu możesz mieć w zapytaniu tablice i obiekty, które są zbierane i sklejane
Na przykład
users[0][firstName]=Amin&users[0][lastName]=Negm&name=Devs&users[1][lastName]=Kienle&users[1][firstName]=Christian
stanie się:
@{ name : @"Devs", users : @[ @{ firstName = @"Amin", lastName = @"Negm" }, @{ firstName = @"Christian", lastName = @"Kienle" } ] }
Możesz o tym myśleć jako o odpowiedniku zapytania URL
NSJSONSerializer
.źródło
Wygląda na to, że używasz go do przetwarzania danych przychodzących z innej aplikacji iOS. Jeśli tak, to właśnie tego używam w tym samym celu.
Pierwsze połączenie (np. W aplikacji zewnętrznej):
UIApplication *application = [UIApplication sharedApplication]; NSURL *url = [NSURL URLWithString:@"myApp://action/1?parameter=2&secondparameter=3"]; if ([application canOpenURL:url]) { [application openURL:url]; NSLog(@"myApp is installed"); } else { NSLog(@"myApp is not installed"); }
Metoda wyodrębnienia danych QueryString z NSURL i zapisania jako NSDictionary:
-(NSDictionary *) getNSDictionaryFromQueryString:(NSURL *)url { NSMutableDictionary *result = [[NSMutableDictionary alloc] init]; NSRange needle = [url.absoluteString rangeOfString:@"?" options:NSCaseInsensitiveSearch]; NSString *data = nil; if(needle.location != NSNotFound) { NSUInteger start = needle.location + 1; NSUInteger end = [url.absoluteString length] - start; data = [url.absoluteString substringWithRange:NSMakeRange(start, end)]; } for (NSString *param in [data componentsSeparatedByString:@"&"]) { NSArray *keyvalue = [param componentsSeparatedByString:@"="]; if([keyvalue count] == 2){ [result setObject:[keyvalue objectAtIndex:1] forKey:[keyvalue objectAtIndex:0]]; } } return result; }
Stosowanie:
NSDictionary *result = [self getNSDictionaryFromQueryString:url];
źródło
Ta klasa jest dobrym rozwiązaniem do analizowania adresów URL.
plik .h
@interface URLParser : NSObject { NSArray *variables; } @property (nonatomic, retain) NSArray *variables; - (id)initWithURLString:(NSString *)url; - (NSString *)valueForVariable:(NSString *)varName; @end
plik .m
#import "URLParser.h" @implementation URLParser @synthesize variables; - (id) initWithURLString:(NSString *)url{ self = [super init]; if (self != nil) { NSString *string = url; NSScanner *scanner = [NSScanner scannerWithString:string]; [scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]]; NSString *tempString; NSMutableArray *vars = [NSMutableArray new]; [scanner scanUpToString:@"?" intoString:nil]; //ignore the beginning of the string and skip to the vars while ([scanner scanUpToString:@"&" intoString:&tempString]) { [vars addObject:[tempString copy]]; } self.variables = vars; } return self; } - (NSString *)valueForVariable:(NSString *)varName { for (NSString *var in self.variables) { if ([var length] > [varName length]+1 && [[var substringWithRange:NSMakeRange(0, [varName length]+1)] isEqualToString:[varName stringByAppendingString:@"="]]) { NSString *varValue = [var substringFromIndex:[varName length]+1]; return varValue; } } return nil; } @end
źródło
Hendrik napisał ładny przykład rozszerzenia w tym pytaniu, jednak musiałem go przepisać, aby nie używać żadnych metod bibliotecznych obiektywnego-c.
NSArray
Szybkie używanie nie jest właściwym podejściem.To jest wynik, wszystko szybkie i trochę bezpieczniejsze. Przykładem użycia będzie mniej linii kodu w Swift 1.2.
public extension NSURL { /* Set an array with all the query items */ var allQueryItems: [NSURLQueryItem] { get { let components = NSURLComponents(URL: self, resolvingAgainstBaseURL: false)! if let allQueryItems = components.queryItems { return allQueryItems as [NSURLQueryItem] } else { return [] } } } /** Get a query item form the URL query :param: key The parameter to fetch from the URL query :returns: `NSURLQueryItem` the query item */ public func queryItemForKey(key: String) -> NSURLQueryItem? { let filteredArray = filter(allQueryItems) { $0.name == key } if filteredArray.count > 0 { return filteredArray.first } else { return nil } } }
Stosowanie:
let queryItem = url.queryItemForKey("myItem")
Lub bardziej szczegółowe użycie:
if let url = NSURL(string: "http://www.domain.com/?myItem=something") { if let queryItem = url.queryItemForKey("myItem") { if let value = queryItem.value { println("The value of 'myItem' is: \(value)") } } }
źródło
Spróbuj tego:
-(NSDictionary *)getUrlParameters:(NSString *)url{ NSArray *justParamsArr = [url componentsSeparatedByString:@"?"]; url = [justParamsArr lastObject]; NSMutableDictionary *params = [[NSMutableDictionary alloc] init]; for (NSString *param in [url componentsSeparatedByString:@"&"]) { NSArray *elts = [param componentsSeparatedByString:@"="]; if([elts count] < 2) continue; [params setObject:[elts lastObject] forKey:[elts firstObject]]; } return params; }
źródło
Dość kompaktowe podejście:
func stringParamsToDict(query: String) -> [String: String] { let params = query.components(separatedBy: "&").map { $0.components(separatedBy: "=") }.reduce(into: [String: String]()) { dict, pair in if pair.count == 2 { dict[pair[0]] = pair[1] } } return params }
źródło
Najbardziej niezawodne rozwiązanie, jeśli używasz adresu URL do przekazywania danych z aplikacji internetowej do telefonu i chcesz przekazywać tablice, liczby, ciągi, ...
JSON koduje twój obiekt w PHP
header("Location: myAppAction://".urlencode(json_encode($YOUROBJECT)));
Wynik dekodowania JSON w iOS
NSData *data = [[[request URL] host] dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *packed = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
źródło