Swift RestKit Post not including post data - swift

I'm not able to get data posted using the following code. I've tried all related posts on SO but still can't get it to work.
Added in request descriptor, have the NSDictionary for mapping the parameters, tried inverseMapping, ect.
var parms = WearRequestParms()
parms.Height = height
parms.Width = width
parms.Density = density
if let userId = AlpineMetricsHttpClient.GetUserId()
{
parms.UserId = userId
}
var objectManager : RKObjectManager?
objectManager = AlpineMetricsHttpClient.SetupClient()
// var mapping = RKObjectMapping(forClass:WearRequestParms.self)
var mapping = RKObjectMapping.requestMapping()
let requestMappingObjects = ["IsCircle","Height","Width","Density","UserId","WearModel","Platform"]
let dict : NSMutableDictionary = ["IsCircle":"IsCircle","Height":"Height","Width":"Width","Density":"Density","UserId":"UserId","WearModel":"WearModel","Platform":"Platform"]
mapping.addAttributeMappingsFromArray(requestMappingObjects)
// mapping.addAttributeMappingsFromDictionary(dict as [NSObject : AnyObject])
// var newRequestMapping = mapping.inverseMapping()
let requestDescriptor = RKRequestDescriptor(mapping: mapping, objectClass: WearRequestParms.self, rootKeyPath: "", method: RKRequestMethod.POST)
objectManager!.addRequestDescriptor(requestDescriptor)
// response
let responseMapping = RKObjectMapping(forClass:PostStatus.self)
var responseDescriptor = RKResponseDescriptor(
mapping: responseMapping
,method:RKRequestMethod.POST
,pathPattern : "/api/User/RegisterWearDevice"
,keyPath :""
,statusCodes : NSIndexSet(index:200))
objectManager!.addResponseDescriptor(responseDescriptor)
RKObjectManager.sharedManager().postObject(parms, path: "/api/User/RegisterWearDevice", parameters: nil,
success:{ operation, mappingResult in
NSLog("success")
defaults.setBool(true, forKey: "WearDimensionsSynced")
},
failure:{ operation, error in
NSLog("Error loading metric list': \(error!.localizedDescription)")
//return nil
}
);

I shouldn't have been using RKObjectManager.sharedManager().postObject
This caused the previous values to get overwritten or interfered with.
I switched
RKObjectManager.sharedManager().postObject
With
objectManager!.postObject

Related

Swift Get Next Page from header of NSHTTPURLResponse

I am consuming an API that gives me the next page in the Header inside a field called Link. (For example Github does the same, so it isn't weird.Github Doc)
The service that I am consuming retrieve me the pagination data in the following way:
As we can see in the "Link" gives me the next page,
With $0.response?.allHeaderFields["Link"]: I get </api/games?page=1&size=20>; rel="next",</api/games?page=25&size=20>; rel="last",</api/games?page=0&size=20>; rel="first".
I have found the following code to read the page, but it is very dirty... And I would like if anyone has dealt with the same problem or if there is a standard way of face with it. (I have also searched if alamofire supports any kind of feature for this but I haven't found it)
// MARK: - Pagination
private func getNextPageFromHeaders(response: NSHTTPURLResponse?) -> String? {
if let linkHeader = response?.allHeaderFields["Link"] as? String {
/* looks like:
<https://api.github.com/user/20267/gists?page=2>; rel="next", <https://api.github.com/user/20267/gists?page=6>; rel="last"
*/
// so split on "," the on ";"
let components = linkHeader.characters.split {$0 == ","}.map { String($0) }
// now we have 2 lines like '<https://api.github.com/user/20267/gists?page=2>; rel="next"'
// So let's get the URL out of there:
for item in components {
// see if it's "next"
let rangeOfNext = item.rangeOfString("rel=\"next\"", options: [])
if rangeOfNext != nil {
let rangeOfPaddedURL = item.rangeOfString("<(.*)>;", options: .RegularExpressionSearch)
if let range = rangeOfPaddedURL {
let nextURL = item.substringWithRange(range)
// strip off the < and >;
let startIndex = nextURL.startIndex.advancedBy(1) //advance as much as you like
let endIndex = nextURL.endIndex.advancedBy(-2)
let urlRange = startIndex..<endIndex
return nextURL.substringWithRange(urlRange)
}
}
}
}
return nil
}
I think that the forEach() could have a better solution, but here is what I got:
let linkHeader = "</api/games?page=1&size=20>; rel=\"next\",</api/games?page=25&size=20>; rel=\"last\",</api/games?page=0&size=20>; rel=\"first\""
let links = linkHeader.components(separatedBy: ",")
var dictionary: [String: String] = [:]
links.forEach({
let components = $0.components(separatedBy:"; ")
let cleanPath = components[0].trimmingCharacters(in: CharacterSet(charactersIn: "<>"))
dictionary[components[1]] = cleanPath
})
if let nextPagePath = dictionary["rel=\"next\""] {
print("nextPagePath: \(nextPagePath)")
}
//Bonus
if let lastPagePath = dictionary["rel=\"last\""] {
print("lastPagePath: \(lastPagePath)")
}
if let firstPagePath = dictionary["rel=\"first\""] {
print("firstPagePath: \(firstPagePath)")
}
Console output:
$> nextPagePath: /api/games?page=1&size=20
$> lastPagePath: /api/games?page=25&size=20
$> firstPagePath: /api/games?page=0&size=20
I used components(separatedBy:) instead of split() to avoid the String() conversion at the end.
I created a Dictionary for the values to hold and removed the < and > with a trim.

How to add "one-to" part of "one-to-many" to fetch results

I want to be able to add the player's data the "to-one" part of the many relationships. The fetch does some aggregation for me, but I would like to know what player it belongs to.
I have a CoreData model that looks like the following:
I have a fetch request that looks like the following:
func statsPerPlayer(player: Players, managedContext: NSManagedObjectContext) -> [String: Int] {
var resultsDic = [String: Int]()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Shifts")
let predicate = NSPredicate(format: "playersRelationship = %#", player)
fetchRequest.predicate = predicate
let nsExpressionForKeyPath = NSExpression(forKeyPath: "timeOnIce")
let nsExpressionForFunctionMin = NSExpression(forFunction: "min:", arguments: [nsExpressionForKeyPath])
let nsExpressionDescriptionMin = NSExpressionDescription()
nsExpressionDescriptionMin.expression = nsExpressionForFunctionMin
nsExpressionDescriptionMin.name = "minShift"
nsExpressionDescriptionMin.expressionResultType = .integer16AttributeType
let nsExpressionForFunctionMax = NSExpression(forFunction: "max:", arguments: [nsExpressionForKeyPath])
let nsExpressionDescriptionMax = NSExpressionDescription()
nsExpressionDescriptionMax.expression = nsExpressionForFunctionMax
nsExpressionDescriptionMax.name = "maxShift"
nsExpressionDescriptionMax.expressionResultType = .integer16AttributeType
let nsExpressionForFunctionSum = NSExpression(forFunction: "sum:", arguments: [nsExpressionForKeyPath])
let nsExpressionDescriptionSum = NSExpressionDescription()
nsExpressionDescriptionSum.expression = nsExpressionForFunctionSum
nsExpressionDescriptionSum.name = "sumShift"
nsExpressionDescriptionSum.expressionResultType = .integer16AttributeType
let nsExpressionForFunctionAvg = NSExpression(forFunction: "average:", arguments: [nsExpressionForKeyPath])
let nsExpressionDescriptionAvg = NSExpressionDescription()
nsExpressionDescriptionAvg.expression = nsExpressionForFunctionAvg
nsExpressionDescriptionAvg.name = "avgShift"
nsExpressionDescriptionAvg.expressionResultType = .integer16AttributeType
let nsExpressionForFunctionCount = NSExpression(forFunction: "count:", arguments: [nsExpressionForKeyPath])
let nsExpressionDescriptionCount = NSExpressionDescription()
nsExpressionDescriptionCount.expression = nsExpressionForFunctionCount
nsExpressionDescriptionCount.name = "countShift"
nsExpressionDescriptionCount.expressionResultType = .integer16AttributeType
fetchRequest.propertiesToFetch = [nsExpressionDescriptionMin, nsExpressionDescriptionMax, nsExpressionDescriptionSum, nsExpressionDescriptionAvg, nsExpressionDescriptionCount]
fetchRequest.resultType = .dictionaryResultType
do {
let fetchArray = try managedContext.fetch(fetchRequest)
print(fetchArray)
resultsDic = fetchArray.first as! [String : Int]
} catch let error as NSError {
print("\(self) -> \(#function): Could not fetch. \(error), \(error.userInfo)")
}
return resultsDic
} //statsPerPlayer
The results look great and something like this:
[{
avgShift = 39;
countShift = 4;
maxShift = 89;
minShift = 6;
sumShift = 157;
}]
However, I would like to include the player that this data is for. How do I add the "to-one" part of the one-to-many relationship in the results?
Thanks!!
In your code above, just add the relevant relationship name to the properties to fetch:
fetchRequest.propertiesToFetch = ["playersRelationship", nsExpressionDescriptionMin, nsExpressionDescriptionMax, nsExpressionDescriptionSum, nsExpressionDescriptionAvg, nsExpressionDescriptionCount]
The dictionaries that are returned will then include the key "playersRelationship" with value set to the NSManagedObjectID of the corresponding Players object. You can then use the context's object(with:) method to access the Players object itself.
Update
So after some testing, it turns out:
a) CoreData gets confused regarding the count aggregate function if you include the relationship in the propertiesToFetch. That leads to the Invalid keypath (request for aggregate operation on a toOne-only keypath error.
b) CoreData gets confused for all the other aggregate functions if you include the relationship in the propertiesToFetch. (It calculates the aggregate across every object, not just those matching the predicate.)
The solution to both problems is to add the relationship as a GROUP BY property. CoreData then calculates the aggregates correctly and also correctly recognises count as a valid operation. So, add the following line:
fetchRequest.propertiesToGroupBy = ["playersRelationship"]

Use SwiftyJSON to get proper data

This is my JSON data, how can I get src data in 0 in pickArray?
"pickArray" : "{\"0\":{\"src\":\"https:\/\/fb-s-d-a.akamaihd.net\/h-ak-xpl1\/v\/t1.0-9\/p720x720\/18010403_1525007564199498_8009700960533638318_n.png?oh=25dbc9c1522dcfdd1d15cdd3e8c0c7da&oe=59997685&__gda__=1502470695_f212ade003e9b1c4ddc6a3ab6cc9e7e7\",\"width\":720,\"height\":720}}"
If I do it like this:
let dataArray = json["pickArray"]
print("dataArray = ",dataArray)
dataArray = {"0":{"src":"https://fb-s-d-a.akamaihd.net/h-ak-xpl1/v/t1.0-9/p720x720/18010403_1525007564199498_8009700960533638318_n.png?oh=25dbc9c1522dcfdd1d15cdd3e8c0c7da&oe=59997685&__gda__=1502470695_f212ade003e9b1c4ddc6a3ab6cc9e7e7","width":720,"height":720}}
But if I do it like this, show null:
let srcArray = dataArray["0"]
print("srcArray = ",srcArray)
I'm using swift3.0
Its looks like that with key pickArray you are having JSON response in String so get that string and convert it data and get JSON from it and then get src from it.
let stringResponse = json["pickArray"].stringValue
if let data = stringResponse.data(using: .utf8) {
let pickArray = JSON(data: data)
//Now access the pickArray to get the src
var sortedKeys = [String]()
if let allKeys = pickArray.dictionaryObject {
sortedKeys = Array(allKeys.keys).sorted { $0.compare($1, options: .numeric) == .orderedAscending }
}
for key in sortedKeys {
print(pickArray[key]["src"].stringValue)
print(pickArray[key]["width"].intValue)
print(pickArray[key]["height"].intValue)
}
}
let srcArray = dataArray["0"].dictionaryObject!
print("srcArray = \(srcArray)")
Now you can access element of "0" value as like below. Hope this work for you.
let jsonScr = JSON(srcArray)
let srcURL = jsonScr["scr"].stringValue

parsing twitter search json data using NSJSONSerialization

I am parsing twiter search api json data with NSJSONSerialization.Requirement is to search tweets by hashtag.In Twitter api console tool I am correctly getting data about 15 tweets.
written code is
if let results: NSDictionary = NSJSONSerialization .JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments , error: errorPointer) as? NSDictionary {
}
I am getting results value as
{
"search_metadata" = {
"completed_in" = "0.05";
count = 15;
"max_id" = 680240431771156480;
"max_id_str" = 680240431771156480;
"next_results" = "?max_id=680240407322689535&q=%23ChristmasEve&include_entities=1";
query = "%23ChristmasEve";
"refresh_url" = "?since_id=680240431771156480&q=%23ChristmasEve&include_entities=1";
"since_id" = 0;
"since_id_str" = 0;
};
statuses = (
{
contributors = "<null>";
coordinates = "<null>";
"created_at" = "Fri Dec 25 04:15:31 +0000 2015";
entities = {
hashtags = (
{
indices = (
0,
13
);
text = ChristmasEve;
},
{
which is incomplete.
I even tried using SwiftyJSon library but I am getting similar results.
Is there any way to get statuses/Tweet info value without using any external library?
Given the fact that you mentioned you are getting multiple tweets (15), the JSON data you're getting back from the API possibly is an array, not a dictionary. It's a good practice to handle both cases when you make network calls:
do {
let object = try NSJSONSerialization.JSONObjectWithData(data, options: [])
if let dictionary = object as? [NSObject: AnyObject] {
// Handle dictionary
} else if let array = object as? [[NSObject: AnyObject]] {
// Handle array
}
} catch {
}

Swift Core Data Quirk

Can anyone help me figure out why this code is behaving thusly...
When opening the app for the first time a "User" is created (if it doesn't already exist, which it doesn't the first time) and then the user is saved along with his/her golf "clubs". I get confirmation of the user saved and the clubs saved in the console. HOWEVER, when I close the app and reopen it the user is fetched but the clubs are not. What am I missing here? Let me know if you need/want to see any screen captures beyond this code...
//MARK: Core Data Variables
var user : User!
var userClubs = NSMutableSet()
var currentRound : Round!
var managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!
func prepareUser() {
let fetchRequest = NSFetchRequest(entityName: "User")
let sortDescriptor = NSSortDescriptor(key: "createdTime", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
if let fetchResults = self.managedObjectContext.executeFetchRequest(fetchRequest, error: nil) as? [User] {
if fetchResults.count > 0 {
self.user = fetchResults[0]
println("First user: \(self.user!.firstName) \(self.user!.lastName)")
let fetchRequestClubs = NSFetchRequest(entityName: "Club")
if let fetchResults2 = self.managedObjectContext.executeFetchRequest(fetchRequestClubs, error: nil) as? [Club] {
if fetchResults2.count > 0 {
println("test: \(fetchResults2[0].type)")
}
}
} else {
println("No user yet")
var newUser : User = NSEntityDescription.insertNewObjectForEntityForName("User", inManagedObjectContext: self.managedObjectContext) as! User
newUser.createdTime = NSDate()
managedObjectContext.save(nil)
var i = 0
println("before array: clubsArray is \(clubsArray.count) clubs long")
var clubs = NSMutableSet.mutableSetValueForKey("clubs")
for newClub in clubsArray {
var club : Club = NSEntityDescription.insertNewObjectForEntityForName("Club", inManagedObjectContext: self.managedObjectContext) as! Club
club.type = clubsArray[i].type as String
club.estimatedMinYardage = clubsArray[i].minDistance as Int
club.estimatedMaxYardage = clubsArray[i].maxDistance as Int
club.lowerBound = clubsArray[i].lowerBound as Int
club.upperBound = clubsArray[i].upperBound as Int
//userClubs.addObject(club)
managedObjectContext.save(nil)
//club.setValue(newUser, forKey: "user")
println("\(club.type)")
i++
}
//user.setValue(userClubs, forKey: "clubs")
prepareUser()
}
}
}
Here's the console output from the first run:
No user yet
before array: clubsArray is 17 clubs long
Putter
LW
SW
PW
9i
8i
7i
6i
5i
5W
... [the rest of the clubs]
First user: Your Name
test: 7i
And from the second run after closing and reopening the app:
First user: Your Name
Bloody hell. I was trying to set 1 of the 17 instances of the Club class to a value that was less than it's minimum value allowed in the data model. If anyone else is having a similar issue check your min/max and default in addition to what #Tom-Harrington suggested in the comments of the original question. Dunno if Apple could get some kind of warning for this kind of thing into future versions of XCode.