4

I have successfully converted the following method from Obj-C to Swift:

After learning how blocks are replaced by closures in Swift.

Obj-C:

- (RACSignal *)fetchCurrentConditionsForLocation:(CLLocationCoordinate2D)coordinate {
    NSString *urlString = [NSString stringWithFormat:@"http://api.openweathermap.org/data/2.5/weather?lat=%f&lon=%f&units=imperial", coordinate.latitude, coordinate.longitude];
    NSURL *url = [NSURL URLWithString:urlString];

    return [[self fetchJSONFromURL:url] map:^(NSDictionary *json) {
        return [MTLJSONAdapter modelOfClass:[WXCondition class] fromJSONDictionary:json error:nil];
    }];
}

Swift:

func fetchCurrentConditionsForLocation(coordinate: CLLocationCoordinate2D) -> RACSignal {
    let urlString = NSString(format: "http://api.openweathermap.org/data/2.5/weather?lat=%f&lon=%f&units=metric", coordinate.latitude, coordinate.longitude)
    let url = NSURL.URLWithString(urlString)

    return fetchJSONFromURL(url).map { json in
        return MTLJSONAdapter.modelOfClass(WXCondition.self, fromJSONDictionary: json as NSDictionary, error: nil)
    }
}

However, I'm having trouble converting the following return map block to Swift:

enter image description here

func fetchHourlyForecastForLocation(coordinate: CLLocationCoordinate2D) -> RACSignal {
    var urlString = NSString(format: "http://api.openweathermap.org/data/2.5/forecast?lat=%f&lon=%f&units=metric&cnt=12", coordinate.latitude, coordinate.longitude)
    let url = NSURL.URLWithString(urlString)

    /* Original Obj-C:

    return [[self fetchJSONFromURL:url] map:^(NSDictionary *json) {
        RACSequence *list = [json[@"list"] rac_sequence];
            return [[list map:^(NSDictionary *item) {
                return [MTLJSONAdapter modelOfClass:[WXCondition class] fromJSONDictionary:item error:nil];
            }] array];
        }];
    }
     */

    // My attempt at conversion to Swift
    // (I can't resolve `rac_sequence` properly). Kind of confused
    // as to how to cast it properly and return
    // it as an "rac_sequence" array.

    return fetchJSONFromURL(url).map { json in
        let list = RACSequence()
        list = [json["list"] rac_sequence]
        return (list).map { item in {
            return MTLJSONAdapter.modelOfClass(WXCondition.self, fromJSONDictionary: item as NSDictionary, error: nil)
        } as NSArray
    }
}

If it helps, this is what rac_sequence is:

- (RACSequence *)rac_sequence {
    return [RACArraySequence sequenceWithArray:self offset:0];
}

RACArraySequence():

+ (instancetype)sequenceWithArray:(NSArray *)array offset:(NSUInteger)offset;

EDIT: The fetch method returns a RACSignal not an NSArray:

func fetchJSONFromURL(url: NSURL) -> RACSignal {

}
Community
  • 1
  • 1
gotnull
  • 26,454
  • 22
  • 137
  • 203
  • 1
    What a well formatted question! One quick comment is to always use initializer syntax. `NSURL(string:urlString)` instead of `NSURL.urlWithString`. You used it for `NSString` but not `NSURL` :p – Jack Jun 14 '14 at 16:52
  • @JackWu: Thanks for the suggestions! Appreciate it! Any particular reason why it's better to use initializer syntax? – gotnull Jun 15 '14 at 03:34
  • 1
    Well in Swift that is the only way to do initialization. No more class initializers vs instance initializers. ObjC initializers and factory methods both get translated into this new syntax automatically. Its the future! – Jack Jun 15 '14 at 04:19

2 Answers2

0

It looks like you simply forgot the return type in the function declaration. The declaration should look something like this:

func fetchHourlyForecastForLocation(coordinate: CLLocationCoordinate2D) -> RACSignal { //...rest of function

Because the return type is now named you can then remove the as NSArray cast in your return statement at the end of the function. Hope this helps!

Christian Di Lorenzo
  • 3,562
  • 24
  • 33
  • I've updated what `fetchJSONFromURL()` returns. It's actually not an `NSArray` it's a `RACSignal`. – gotnull Jun 15 '14 at 03:27
  • Yeah, although there's still a lot of code that doesn't compile. That's not the only change that's needed to port that function over. – gotnull Jun 16 '14 at 00:16
  • One thing I forgot to mention: if you have a collection you have to put angle brackets and say what it will contain (e.g `Array` for a list of integers). – Christian Di Lorenzo Jun 16 '14 at 10:59
0

Try this :

func fetchHourlyForecastForLocation(coordinate: CLLocationCoordinate2D,completion:(AnyObject) -> Void)  {

   //after getting the NSArray (maping)
   completion(_array)
}
alexsc
  • 1,196
  • 1
  • 11
  • 21