0

I am building a feed with links to multimedia assets. If a link is bad it should not be in the feed as a video that does not play or image that does not load is a poor user experience. The feed is pulled by the phone via JSON from an endpoint without the benefit of a websocket.

I can test the links before putting them in the feed, however, waiting to verify a link takes time and if the feed has many items, I'm anticipating slow loading times.

Even accepting the delay for validating links, I am struggling with how to implement asynchronous calls to the links inside a synchronous conversion process once we have downloaded the data.

Here is the workflow.

  1. Asynchronously import JSON as object. You get a JSON object such as:

    {"feed":[{"title":"Check out this video","videosurl":"https://www.youtube.com/somevideo.mp4"}]}

  2. Serialize JSON into Array of feed objects (synchronous)

  3. Save the array of Feed objects to Core Data (synchronous)

  4. Display the objects using an NSFetchedResultsController. (synchronous)

Inside 3-just before saving each item to Core Data would seem like a logical place to test/validate the links.

Here is my code so far inside of Step 3 (changed to use function B)

-(void) saveFeed:(NSArray *)items inContext: (NSManagedObjectContext*) context
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Videofeed" inManagedObjectContext:context];
    items* item;
    for (i=0;i<max;i++){ 
        item = items[i];
NSString * link = item.videosurl;
    __block BOOL validFile = NO;
        [link foundValidFileAtSurlWithCompletion:^(BOOL __validFile) {
                   
          
                     }];
                if (validFile!=YES) {
                  //  continue;//skip this one
                }
                
            NSManagedObject *record = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:context];
            [record setValue:title forKey:@"title"];
            [record setValue:videosurl forKey:@"videosurl"];
        }
        [context save]
    };//save context
}

Function A

@objc public extension NSString {
    
    @available(iOS 13.0.0, *)
    func fileExists(at surl: NSString) async throws -> Bool {
        let str = self as String
            
        guard let url =  URL(string: str) else { return false }
           
        var request = URLRequest(url: url)
        request.httpMethod = "HEAD"
        request.timeoutInterval = 1.0 // Adjust to your needs
        let (_, response) = try await URLSession.shared.data(for: request)
        return (response as? HTTPURLResponse)?.statusCode == 200
     }
}

Edit:

I have implemented the following code that uses a completionHandler to check for a valid URL and it returns a BOOL of yes or no, however, I don't have a way to hold up the synchronous code to wait for a response. How can I do this from Objective-C?

Function B

@objc public extension NSString {
func foundValidFileAtSurl(completion:@escaping (Bool) -> ()) {
       
        let str = self as String
     
        if (self == "") {
            completion(false)
        }
        if let url = URL(string: str) {
            
            var request = URLRequest(url: url)
            request.httpMethod = "HEAD"//confirm header not complete file
            request.timeoutInterval = 1.0 // Adjust to your needs
            let task = URLSession.shared.dataTask(with: request) {
                data,response,error  in
                guard error == nil else { print(error ?? "error",error!.localizedDescription); return }
                guard data != nil else { print("Empty data"); return }
               // flag = ((response as? HTTPURLResponse)?.statusCode == 200)
                completion((response as? HTTPURLResponse)?.statusCode == 200)
            }
            task.resume()
        }
    }
}
5
  • Are you mixing Swift and Objective-C code? If you also write saveFeed in Swift, you can make that async and you will be able to await. Otherwise you'll have to use completion handlers like the old days. Commented Sep 10, 2024 at 0:49
  • I've tidied up the code formatting a bit. I am concerned that you seem to be mixing Objective-C and Swift, so separated the two fragments. There were also unbalanced square brackets and braces in the fragments. Are you sure this is real code? Commented Sep 10, 2024 at 9:50
  • Oh yes, and as @Sweeper says, don't think await is supported on Objective-C. If you have the choice, write everything in Swift. Commented Sep 10, 2024 at 9:54
  • this is an older hybrid app written largely in Objective C with some Swift and this feed feature is in the Objective-C part. However, I thought it might make sense to handle the validate remote file link in a swift extension so it can easily be referenced when needed. @Sweeper I have not succeeded in figuring how to call await from Objective C so perhaps I have to use completion handler but haven't figured out syntax to successfully call from Objc. Commented Sep 10, 2024 at 12:07
  • Posted separate question on error trying to use completionHandler approach here: stackoverflow.com/questions/78969726/… Commented Sep 10, 2024 at 13:29

1 Answer 1

0

Swift Approach

if let url = URL(string: "https://example.com") {
    // The URL is valid, you can proceed with further checks.
    debugPrint("Valid URL format")
} else {
    debugPrint("Invalid URL format")
}

Objective-C Approach

NSString *urlString = @"https://example.com";
NSURL *url = [NSURL URLWithString:urlString];

if (url && url.scheme && url.host) {
    NSLog(@"Valid URL format");
} else {
    NSLog(@"Invalid URL format");
}
Sign up to request clarification or add additional context in comments.

1 Comment

This just validates the URL. Question requires that the object referenced is valid too.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.