Tengo una URL como myApp://action/1?parameter=2&secondparameter=3
Con la consulta de propiedad obtengo siguiendo parte de mi URL
parameter=2&secondparameter=3
¿Hay alguna forma fácil de poner esto en un NSDictionary
o en un Array
?
Muchas gracias
iphone
objective-c
nsurl
gabac
fuente
fuente
[params setObject:[elts lastObject] forKey:[elts firstObject]];
su lugar: es más seguroPuede usar
queryItems
enURLComponents
.Rápido
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)
Alternativamente, puede agregar una extensión en la URL para facilitar las cosas.
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 } }
A continuación, puede acceder al parámetro por su nombre.
let url = "http://example.com?param1=value1¶m2=param2" print(url.queryParameters["param1"])
fuente
http://example.com/abc#abc?param1=value1¶m2=param2
queryItems será nuloTenía motivos para escribir algunas extensiones para este comportamiento que podrían resultar útiles. Primero el encabezado:
#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
Estos métodos amplían NSString, NSURL y NSDictionary, para permitirle convertir hacia y desde cadenas de componentes de consulta y objetos de diccionario que contienen los resultados.
Ahora el código .m relacionado:
#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
fuente
Prueba esto ;)!
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]]; }
fuente
Todas las publicaciones anteriores no codifican correctamente la URL. Sugeriría los siguientes métodos:
+(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]; }
fuente
if(!query||[query length] == 0)
es redundante. Puede verificar con seguridadif([query length] == 0)
como en el caso de quequery == nil
devuelva el valor de0
si intenta llamar a length en él.NSUTF8StringEncoding
insplitQuery
para admitir todos los conjuntos de caracteres :) Además,[string stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]
es una forma más nueva de codificarconcatenateQuery
.Aquí está la extensión en rápido:
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 } }
fuente
De acuerdo con la respuesta ya muy limpia de Onato , escribí una extensión para NSURL en Swift donde puede obtener un parámetro de consulta como este:
por ejemplo, la URL contiene el par param = some_value
let queryItem = url.queryItemForKey("param") let value = queryItem.value // would get String "someValue"
La extensión se parece a:
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 } }
fuente
Para aquellos que usan Bolts Framework , puede usar:
NSDictionary *parameters = [BFURL URLWithURL:yourURL].inputQueryParameters;
Recuerde importar:
#import <Bolts/BFURL.h>
Si tiene Facebook SDK en su proyecto, también tiene Bolts . Facebook está utilizando este marco como dependencia.
fuente
BFURL(url: url)?.inputQueryParameters?["myKey"] as? String
La forma preferida de tratar las URL es ahora
NSURLComponents
. En particular, laqueryItems
propiedad que devuelve unNSArray
de params.Si quieres los parámetros en a
NSDictionary
, aquí tienes un método:+(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; }
Advertencia: las URL pueden tener parámetros repetidos, pero el diccionario solo contendrá el último valor de cualquier parámetro duplicado. Si eso no es deseable, use la
queryItems
matriz directamente.fuente
Swift 2.1
Un trazador de líneas:
"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"]
Usado como una extensión en 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 [:] } } } }
Ejemplo:
let url = NSURL(string: "http://example.com?p1=v1&p2=v2")! let queryDict = url.queryValues // ["p1": "v1", "p2": "v2"]
Tenga en cuenta que si usa OS X 10.10 o iOS 8 (o posterior), probablemente sea mejor usar
NSURLComponents
y laqueryItems
propiedad y crear el diccionarioNSURLQueryItems
directamente desde.Aquí hay una solución de extensión
NSURLComponents
basadaNSURL
: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 } } }
Una nota al pie de la extensión NSURL es que en realidad es posible en Swift darle a la propiedad el mismo nombre que la propiedad de cadena existente—
query
. No lo supe hasta que lo probé, pero el polimorfismo en Swift te permite diferenciar solo en el tipo de retorno. Entonces, si la propiedad NSURL extendida espublic var query: [String:String]
, funciona. No utilicé esto en el ejemplo porque lo encuentro un poco loco, pero funciona ...fuente
Publiqué una clase simple haciendo el trabajo bajo MIT:
https://github.com/anegmawad/URLQueryToCocoa
Con él puede tener matrices y objetos en la consulta, que se recopilan y pegan juntos
Por ejemplo
users[0][firstName]=Amin&users[0][lastName]=Negm&name=Devs&users[1][lastName]=Kienle&users[1][firstName]=Christian
se convertirá:
@{ name : @"Devs", users : @[ @{ firstName = @"Amin", lastName = @"Negm" }, @{ firstName = @"Christian", lastName = @"Kienle" } ] }
Puede considerarlo como una contraparte de consulta de URL de
NSJSONSerializer
.fuente
Parece que lo está utilizando para procesar datos entrantes de otra aplicación de iOS. Si es así, esto es lo que uso para el mismo propósito.
Llamada inicial (por ejemplo, en una aplicación externa):
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"); }
Método para extraer datos QueryString de NSURL y guardarlos como 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; }
Uso:
NSDictionary *result = [self getNSDictionaryFromQueryString:url];
fuente
Esta clase es una buena solución para el análisis de URL.
archivo .h
@interface URLParser : NSObject { NSArray *variables; } @property (nonatomic, retain) NSArray *variables; - (id)initWithURLString:(NSString *)url; - (NSString *)valueForVariable:(NSString *)varName; @end
archivo .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
fuente
Hendrik escribió un buen ejemplo de extensión en esta pregunta, sin embargo, tuve que volver a escribirlo para no usar ningún método de biblioteca de objetivo-c. Usar
NSArray
rápido no es el enfoque correcto.Este es el resultado, todo rápido y un poco más seguro. El ejemplo de uso será menos líneas de código con 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 } } }
Uso:
let queryItem = url.queryItemForKey("myItem")
O, uso más detallado:
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)") } } }
fuente
prueba esto:
-(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; }
fuente
Enfoque bastante compacto:
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 }
fuente
La solución más robusta si está utilizando una URL para pasar datos desde la aplicación web al teléfono y desea pasar matrices, números, cadenas, ...
JSON codifica tu objeto en PHP
header("Location: myAppAction://".urlencode(json_encode($YOUROBJECT)));
Y JSON decodifica el resultado en iOS
NSData *data = [[[request URL] host] dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *packed = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
fuente